Alexa (Echo) with ESP32 and ESP8266 – Voice Controlled Relay
In this project, you’re going to learn how to control the ESP8266 or the ESP32 with voice commands using Alexa (Amazon Echo Dot). As an example, we’ll control two 12V lamps connected to a relay module. We’ll also add two 433 MHz RF wall panel switches to physically control the lamps.Note : this tutorial is compatible with all Echo Dot generations and with the latest fauxmoESP library (3.1.0). It works with ESP32 and ESP8266.
Watch the Project Video Demonstration This project works both with ESP8266 and ESP32. We provide instructions for both development boards. Before getting straight to the project, read this section to see what you’ll achieve by the end of this project.
Project Overview Control Lamps using Alexa
By the end of this project you’ll be able to control two lamps (lamp 1 and lamp 2) with voices commands using Alexa. The figure below shows a high-level overview on how the project works to control lamp 1 – it works similarly for lamp 2.Alexa will respond to the following commands: “Alexa, turn on lamp 1” “Alexa, turn off lamp 1” “Alexa, turn on lamp 2” “Alexa, turn on lamp 2” “Alexa, turn on lamps” turns on both lamps “Alexa, turn off lamps” turns off both lamps When you say something like “Alexa, turn on lamp 1”, the ESP8266 or ESP32 will trigger a relay to turn on lamp 1. When you say something like“Alexa, turn off lamp 1”, the ESP8266 or ESP32 will send a signal to the relay to turn off the lamp. This works similarly for lamp 2.
Control Lamps using 433 MHz Wall Switches
In this project, we’ll also add two 433 MHz wall switches to physically control the lamps. You’ll have a switch for each lamp. The switch changes the lamp’s state to the opposite of its current state. For example, if the lamp is off, press the wall switch to turn it on. To turn it off, you just need to press the switch again. Take a look at the figure below that illustrates how it works.![]()
Here’s a complete list of the parts required for this project (click the links below to find the best price at Maker Advisor ):
Parts Required ESP Board (you can use either ESP32 or ESP8266): ESP8266 – read Best ESP8266 Wi-Fi Development Boards ESP32 – we use the ESP32 DOIT DEVKIT V1 Board– 36 GPIOs (read ESP32 development boards comparison ) Alexa – Echo, Echo Show or Echo Dot
(read the next section for more details) 433 MHz RF Wall Panel Switch 433 MHz transmitter/receiver 12V 2A power adaptor Step-down buck converter Relay module 12V lamp 12V lamp holder Male DC barrel jack 2.1mm Stripboard or breadboard Jumper WiresYou can use the links below to buy an Amazon Echo. There are several models available – all of them are compatible with this project.
How to Buy An Amazon Echo ![]()
The 433 MHz RF wall panel switch is a great way to remotely control devices. It can be easily attached to a wall with adhesive tap, without the need to make holes on the walls. Additionally, it is wireless, so you don’t need to worry about wiring and then hiding cables. In this project we’re using two wall panel switches. Instead, you can use a panel switch with two buttons – there are also another version with three switches.
433 MHz RF Wall Panel Switch This wall panel switchhas a push button in its circuit, as shown in the figure below, that when pressed emits a 433 MHz signal. You can use that signal to control whatever you want. This wall panel switch uses a 27A 12V type battery (not included in the package). So, you may want to buy one, when you get your wall panel switch.
![]()
When you press the 433 MHz wall panel switch, it sends a 433 MHz signal. You need to decode that signal using a 433 MHz receiver. To learn how to decode the 433 MHz signal read the following post: Decode and Send 433 MHz RF Signals with Arduino – read the “Decoder Sketch” part. The sketch works with Arduino, ESP32, and ESP8266. Take note of the decimal (24Bit) code for each of your switches, because you’ll need them later.
Decode the Wall Panel Switch 433 MHz RF Signals In my case: switch 1:
6819768 switch 2:9463928 You should get different values. You’ll then use these signals in your ESP8266 or ESP32 sketch. When you press the switch, it sends a 433 MHz signal. This signal is detected by the receiver that is connected to the ESP. This way, the ESP knows the switch was pressed and it inverts the lamp’s current state.![]()
To control your ESP8266 or ESP32 with Amazon Echo, you need to install the FauxmoESP library. This library emulates a Belkin Wemo device, allowing you to control your ESP32 or ESP8266 using this protocol.This way, the Echo or Echo Dot instantly recognizes the device, after uploading the code, without any extra skills or third party services. You can read more about FauxmoESP here .
The FauxmoESP Installing the FauxmoESP Library Click here to download the FauxmoESP library . You should have a .zip folder in your Downloads Unzip the.zipfolder and you should getxoseperez-fauxmoesp-50cbcf3087fd folder Rename your folder fromtoxoseperez-fauxmoesp-50cbcf3087fd xoseperez_fauxmoesp Move the xoseperez_fauxmoesp folder to your Arduino IDE installationlibraries folder Finally, re-open your Arduino IDEFollow these next instructions if you’re using an ESP8266.
Alexa – Echo Dot with ESP8266 Installing the ESP8266 Board in Arduino IDE In order to upload code to your ESP8266 using Arduino IDE, you should install an add-on for the Arduino IDE that allows you to program the ESP8266 using the Arduino IDE and its programming language. If you haven’t installed the ESP8266 add-on for the Arduino IDE, follow the next tutorial: How to Install the ESP8266 Board in Arduino IDE .Installing the ESPAsyncTCP Library You also need to install theESPAsyncTCP Library library. Follow the next instructions to install it: Click here to download the ESPAsyncTCP library . You should have a .zip folder in your Downloads Unzip the.zipfolder and you should getESPAsyncTCP-master folder Rename your folder fromE toSPAsyncTCP-master ESPAsyncTCP Move the ESPAsyncTCP folder to your Arduino IDE installationlibraries folder Finally, re-open your Arduino IDESchematic
If you’re using an ESP8266 board, assemble your circuit by following the next schematic diagram – you can click the image to zoom.If you’re having trouble following the circuit diagram, you can use the following table as a reference:
| ESP8266 | Connect to |
| GPIO 5 | 433 MHz receiver data pin |
| GPIO 4 | Relay IN1 pin |
| GPIO 14 | Relay IN2 pin |
If you’re having trouble following the circuit diagram, you can use the following table as a reference:
| ESP32 | Connect to |
| GPIO 13 | 433 MHz receiver data pin |
| GPIO 14 | Relay IN1 pin |
| GPIO 12 | Relay IN2 pin |
Alternatively, you can also discover devices using the Amazon Alexa app, by following the steps shown in the figure below.
Then, ask Alexa to turn on/off the lamps.
You’ll also get information about the lamps state on the Serial Monitor.
After making sure everything is working properly, you can turn your circuit into a permanent solution.
Now you can ask Alexa to control your lamps with the following voice commands:
“Alexa, turn on lamp 1”
“Alexa, turn off lamp 1”
“Alexa, turn on lamp 2”
“Alexa, turn on lamp 2”
You can also control both lamps at the same time by creating a group in the Amazon Alexa app.
We called it “lamps”.
Now, you can control both lamps at the same time, using the following voice commands.
“Alexa, turn on lamps”
“Alexa, turn off lamps”
You can also physically control your lamps using the 433 MHz wall panel switches.
For a getting started guide for the BMP388, check the following tutorial: ESP32 with BMP388 Barometric/Altimeter Sensor (Arduino IDE)
The ESP32 sets an access point (
The ESP32 is connected to a BMP388 pressure sensor, a microSD card module, an OLED display and a pushbutton.
Every minute (or other period of time you define in the code), the ESP32 records new sensor readings to a file on the microSD card (
DOIT ESP32 DEVKIT V1 Board – read Best ESP32 Development Boards
BMP388 sensor module ( Guide for BMP388 )
MicroSD card module + microSD card
Pushbutton
10k Ohm resistor
Breadboard
Jumper wires
You can also check the wiring in the following table:
| BMP388 | GPIO 21 (SDA), GPIO 22 (SCL) |
| OLED Display | GPIO 21 (SDA), GPIO 22 (SCL) |
| MicroSD card Module | GPIO 5 (CS), GPIO 23 (MOSI), GPIO 18 (CLK), GPIO 19 (MISO) |
| Pushbutton | GPIO 4 |
*In my case, it shows “File already exists”.
But, when you’re running it for the first time, it should show “File doesn’t exist”, “Creating file …”.
After a few seconds, it will display the first readings.
After that, if you want to get more accurate altitude readings, on your computer or smartphone, connect to the ESP32 access point.
Open a browser and go to the 192.168.4.1 IP address and insert the current sea level pressure at your location.
After you’ve clicked the submit button, you’ll see the inserted value on the Serial Monitor.
If you click on the pushbutton, you can check the current temperature and altitude on the OLED display.
If you want to check all the readings, you just need to connect the microSD card to your computer, and you can access the data.txt file with all the records.
To analyze your data, you can use Google Sheets, Excel, or other software.
Have you visited Pico Island or the Azores? Let us know in the comments below.
| Pushbutton | GPIO 33 |
| Trimpot | GPIO 32 |
| Photoresistor (LDR) | GPIO 4 |
| DHT22 data pin | GPIO 15 |
| LED1 | GPIO 27 |
| LED2 | GPIO 26 |
| BMP180 | SDA(GPIO 21); SCL(GPIO 22) |
| SD card module | MOSI(GPIO 23); MISO(GPIO 19): CLK(GPIO 18); CS(GPIO 5) |
| Free GPIOs (terminal blocks) | GPIO14, GPIO13, GPIO12 |
3.
You’ll see a success message at the bottom.
Then, you can use the “Gerber Viewer” link at the bottom right corner to check if everything went as expected.
You can view the top and bottom of the PCB.
You can view or hide the solder-mask, silkscreen, copper, etc.
With the default settings, you can order 10 PCBs for just $2.
However, if you want to select other settings like a different PCB Color it will cost you a few more dollars.
When, you’re happy with your order.
Click the “
My PCBs took 1 day to be manufactured and they arrived in 5 business days using DHL delivery option.
Taking a closer look at the PCBs, I must say that I’m really impressed with the quality.
I don’t think you can get a better PCB service for this price.
Here’s a list of all the components you need to solder on the PCB:
2x SMD LEDs
2x 330 Ohm SMD resistors
1x 10k Ohm SMD resistor
1x 4.7k Ohm SMD resistor
1x Trimpot (10k)
1x Pushbutton
1x SD card module
1x BMP180 barometric sensor
1x DHT22 temperature and humidity sensor
2x Screw terminal blocks
Female pin header socket
ESP32 DOIT DEVKIT V1 Board (version with 30 GPIOs) – you can get this board from Banggood , or
The following figure shows how the PCB looks like after soldering all the components.
Now, everything should be ready.
By the end of the project, you have your own ESP32 weather station web server, and all the hardware is well compacted on a PCB.
Open your browser, type the IP address and you should see a table with the latest sensor readings.
The web server displays the DHT22, BMP180, potentiometer and LDR readings.
The readings are updated every 10 seconds without the need to refresh the web page.
To update the readings without refreshing the web page, we use AJAX.
As you can read here , AJAX is a developer’s dream, because it can update the web page without reloading the page, request and receive data from a server, after the page has loaded, and send data to a server in the background.
Updated on 27 March 2023
Previously, we’ve stored sensor readings in a database and displayed them on a table or charts that you can access from anywhere using your own server.
Now, I’ve decided to take a few steps further and add some more information to the web page.
I’ve added two gauges to display the latest temperature and humidity readings as well as some statistics about the minimum, maximum and average readings from a number of readings that you can define.
You can also visualize all the latest readings on a table and you can select how many readings you want to show.
To build this project, you’ll use these technologies:
ESP32 or ESP8266 programmed with Arduino IDE
Hosting server and domain name
PHP script to insert data into MySQL and display it on a web page
MySQL database to store readings
This project is divided into the following main sections:
You have an ESP32 or ESP8266 that sends sensor readings to your own server.
For this, you have your board connected to your router;
In your server, there’s a PHP script that allows you to store your readings in a MySQL database;
Then, another PHP script will display the web page with the gauges, table, and all the other information;
Finally, you can visualize the readings from anywhere in the world by accessing your own domain name.
That’s it! Your new database and user were created successfully.
Now, save all your details because you’ll need them later:
In the left sidebar, select your database name example_esp_data and open the “SQL” tab.
After that, you should see your newly created table called SensorData in the example_esp_data database as shown in the figure below:
Edit the newly created file (esp-post-data.php) and copy the following snippet:
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com/cloud-weather-station-esp32-esp8266/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<?php
include_once('esp-database.php');
// Keep this API Key value to be compatible with the ESP code provided in the project page.
If you change this value, the ESP sketch needs to match
$api_key_value = "tPmAT5Ab3j7F9";
$api_key= $sensor = $location = $value1 = $value2 = $value3 = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$api_key = test_input($_POST["api_key"]);
if($api_key == $api_key_value) {
$sensor = test_input($_POST["sensor"]);
$location = test_input($_POST["location"]);
$value1 = test_input($_POST["value1"]);
$value2 = test_input($_POST["value2"]);
$value3 = test_input($_POST["value3"]);
$result = insertReading($sensor, $location, $value1, $value2, $value3);
echo $result;
}
else {
echo "Wrong API Key provided.";
}
}
else {
echo "No data posted with HTTP POST.";
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
View raw code
Copy that PHP script:
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com/cloud-weather-station-esp32-esp8266/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<?php
$servername = "localhost";
// REPLACE with your Database name
$dbname = "REPLACE_WITH_YOUR_DATABASE_NAME";
// REPLACE with Database user
$username = "REPLACE_WITH_YOUR_USERNAME";
// REPLACE with Database user password
$password = "REPLACE_WITH_YOUR_PASSWORD";
function insertReading($sensor, $location, $value1, $value2, $value3) {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "INSERT INTO SensorData (sensor, location, value1, value2, value3)
VALUES ('" .
$sensor .
"', '" .
$location .
"', '" .
$value1 .
"', '" .
$value2 .
"', '" .
$value3 .
"')";
if ($conn->query($sql) === TRUE) {
return "New record created successfully";
}
else {
return "Error: " .
$sql .
"<br>" .
$conn->error;
}
$conn->close();
}
function getAllReadings($limit) {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT id, sensor, location, value1, value2, value3, reading_time FROM SensorData order by reading_time desc limit " .
$limit;
if ($result = $conn->query($sql)) {
return $result;
}
else {
return false;
}
$conn->close();
}
function getLastReadings() {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT id, sensor, location, value1, value2, value3, reading_time FROM SensorData order by reading_time desc limit 1" ;
if ($result = $conn->query($sql)) {
return $result->fetch_assoc();
}
else {
return false;
}
$conn->close();
}
function minReading($limit, $value) {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT MIN(" .
$value .
") AS min_amount FROM (SELECT " .
$value .
" FROM SensorData order by reading_time desc limit " .
$limit .
") AS min";
if ($result = $conn->query($sql)) {
return $result->fetch_assoc();
}
else {
return false;
}
$conn->close();
}
function maxReading($limit, $value) {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT MAX(" .
$value .
") AS max_amount FROM (SELECT " .
$value .
" FROM SensorData order by reading_time desc limit " .
$limit .
") AS max";
if ($result = $conn->query($sql)) {
return $result->fetch_assoc();
}
else {
return false;
}
$conn->close();
}
function avgReading($limit, $value) {
global $servername, $username, $password, $dbname;
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT AVG(" .
$value .
") AS avg_amount FROM (SELECT " .
$value .
" FROM SensorData order by reading_time desc limit " .
$limit .
") AS avg";
if ($result = $conn->query($sql)) {
return $result->fetch_assoc();
}
else {
return false;
}
$conn->close();
}
?>
View raw code
Before saving the file, you need to modify the $dbname, $username and $password variables with your unique details:
// Your Database name
$dbname = "example_esp_data";
// Your Database user
$username = "example_esp_board";
// Your Database user password
$password = "YOUR_USER_PASSWORD";
After adding the database name, username and password, save the file and continue with this tutorial.
If you try to access your domain name in the next URL path, you’ll see the following:
https://example.com/esp-post-data.php
Copy that CSS to your file and save it:
/**
Rui Santos
Complete project details at https://RandomNerdTutorials.com/cloud-weather-station-esp32-esp8266/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
**/
body {
width: 60%;
margin: auto;
text-align: center;
font-family: Arial;
top: 50%;
left: 50%;
}
@media screen and (max-width: 800px) {
body {
width: 100%;
}
}
table {
margin-left: auto;
margin-right: auto;
}
div {
margin-left: auto;
margin-right: auto;
}
h2 { font-size: 2.5rem; }
.header {
padding: 1rem;
margin: 0 0 2rem 0;
background: #f2f2f2;
}
h2{
font-size: 2rem;
font-family: Arial, sans-serif;
text-align: center;
text-transform: uppercase;
}
.content {
display: flex;
}
@media screen and (max-width: 500px) /* Mobile */ {
.content {
flex-direction: column;
}
}
.mask {
position: relative;
overflow: hidden;
display: block;
width: 12.5rem;
height: 6.25rem;
margin: 1.25rem;
}
.semi-circle {
position: relative;
display: block;
width: 12.5rem;
height: 6.25rem;
background: linear-gradient(to right, #3498db 0%, #05b027 33%, #f1c40f 70%, #c0392b 100%);
border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}
.semi-circle::before {
content: "";
position: absolute;
bottom: 0;
left: 50%;
z-index: 2;
display: block;
width: 8.75rem;
height: 4.375rem;
margin-left: -4.375rem;
background: #fff;
border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}
.semi-circle--mask {
position: absolute;
top: 0;
left: 0;
width: 12.5rem;
height: 12.5rem;
background: transparent;
transform: rotate(120deg) translate3d(0, 0, 0);
transform-origin: center center;
backface-visibility: hidden;
transition: all 0.3s ease-in-out;
}
.semi-circle--mask::before {
content: "";
position: absolute;
top: 0;
left: 0%;
z-index: 2;
display: block;
width: 12.625rem;
height: 6.375rem;
margin: -1px 0 0 -1px;
background: #f2f2f2;
border-radius: 50% 50% 50% 50% / 100% 100% 0% 0%;
}
.gauge--2 .semi-circle { background: #3498db; }
.gauge--2 .semi-circle--mask { transform: rotate(20deg) translate3d(0, 0, 0); }
#tableReadings { border-collapse: collapse; }
#tableReadings td, #tableReadings th {
border: 1px solid #ddd;
padding: 10px;
}
#tableReadings tr:nth-child(even){ background-color: #f2f2f2; }
#tableReadings tr:hover { background-color: #ddd; }
#tableReadings th {
padding: 10px;
background-color: #2f4468;
color: white;
}
View raw code
Finally, create another PHP file in the
Edit the newly created file (esp-weather-station.php) and copy the following code:
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com/cloud-weather-station-esp32-esp8266/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<?php
include_once('esp-database.php');
if (isset($_GET["readingsCount"])){
$data = $_GET["readingsCount"];
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
$readings_count = $_GET["readingsCount"];
}
// default readings count set to 20
else {
$readings_count = 20;
}
$last_reading = getLastReadings();
$last_reading_temp = $last_reading["value1"];
$last_reading_humi = $last_reading["value2"];
$last_reading_time = $last_reading["reading_time"];
// Uncomment to set timezone to - 1 hour (you can change 1 to any number)
//$last_reading_time = date("Y-m-d H:i:s", strtotime("$last_reading_time - 1 hours"));
// Uncomment to set timezone to + 7 hours (you can change 7 to any number)
//$last_reading_time = date("Y-m-d H:i:s", strtotime("$last_reading_time + 7 hours"));
$min_temp = minReading($readings_count, 'value1');
$max_temp = maxReading($readings_count, 'value1');
$avg_temp = avgReading($readings_count, 'value1');
$min_humi = minReading($readings_count, 'value2');
$max_humi = maxReading($readings_count, 'value2');
$avg_humi = avgReading($readings_count, 'value2');
?>
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="esp-style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<header>
<h1> ESP Weather Station</h2>
<form method="get">
<input type="number" name="readingsCount" min="1" placeholder="Number of readings (<?php echo $readings_count; ?>)">
<input type="submit" value="UPDATE">
</form>
</header>
<body>
<p>Last reading: <?php echo $last_reading_time; ?></p>
<section>
<div>
<h3>TEMPERATURE</h3>
<div>
<div></div>
<div></div>
</div>
<p>--</p>
<table cellspacing="5" cellpadding="5">
<tr>
<th colspan="3">Temperature <?php echo $readings_count; ?> readings</th>
</tr>
<tr>
<td>Min</td>
<td>Max</td>
<td>Average</td>
</tr>
<tr>
<td><?php echo $min_temp['min_amount']; ?> °C</td>
<td><?php echo $max_temp['max_amount']; ?> °C</td>
<td><?php echo round($avg_temp['avg_amount'], 2); ?> °C</td>
</tr>
</table>
</div>
<div>
<h3>HUMIDITY</h3>
<div>
<div></div>
<div></div>
</div>
<p>--</p>
<table cellspacing="5" cellpadding="5">
<tr>
<th colspan="3">Humidity <?php echo $readings_count; ?> readings</th>
</tr>
<tr>
<td>Min</td>
<td>Max</td>
<td>Average</td>
</tr>
<tr>
<td><?php echo $min_humi['min_amount']; ?> %</td>
<td><?php echo $max_humi['max_amount']; ?> %</td>
<td><?php echo round($avg_humi['avg_amount'], 2); ?> %</td>
</tr>
</table>
</div>
</section>
<?php
echo '<h2> View Latest ' .
$readings_count .
' Readings</h2>
<table cellspacing="5" cellpadding="5">
<tr>
<th>ID</th>
<th>Sensor</th>
<th>Location</th>
<th>Value 1</th>
<th>Value 2</th>
<th>Value 3</th>
<th>Timestamp</th>
</tr>';
$result = getAllReadings($readings_count);
if ($result) {
while ($row = $result->fetch_assoc()) {
$row_id = $row["id"];
$row_sensor = $row["sensor"];
$row_location = $row["location"];
$row_value1 = $row["value1"];
$row_value2 = $row["value2"];
$row_value3 = $row["value3"];
$row_reading_time = $row["reading_time"];
// Uncomment to set timezone to - 1 hour (you can change 1 to any number)
//$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time - 1 hours"));
// Uncomment to set timezone to + 7 hours (you can change 7 to any number)
//$row_reading_time = date("Y-m-d H:i:s", strtotime("$row_reading_time + 7 hours"));
echo '<tr>
<td>' .
$row_id .
'</td>
<td>' .
$row_sensor .
'</td>
<td>' .
$row_location .
'</td>
<td>' .
$row_value1 .
'</td>
<td>' .
$row_value2 .
'</td>
<td>' .
$row_value3 .
'</td>
<td>' .
$row_reading_time .
'</td>
</tr>';
}
echo '</table>';
$result->free();
}
?>
<script>
var value1 = <?php echo $last_reading_temp; ?>;
var value2 = <?php echo $last_reading_humi; ?>;
setTemperature(value1);
setHumidity(value2);
function setTemperature(curVal){
//set range for Temperature in Celsius -5 Celsius to 38 Celsius
var minTemp = -5.0;
var maxTemp = 38.0;
//set range for Temperature in Fahrenheit 23 Fahrenheit to 100 Fahrenheit
//var minTemp = 23;
//var maxTemp = 100;
var newVal = scaleValue(curVal, [minTemp, maxTemp], [0, 180]);
$('.gauge--1 .semi-circle--mask').attr({
style: '-webkit-transform: rotate(' + newVal + 'deg);' +
'-moz-transform: rotate(' + newVal + 'deg);' +
'transform: rotate(' + newVal + 'deg);'
});
$("#temp").text(curVal + ' oC');
}
function setHumidity(curVal){
//set range for Humidity percentage 0 % to 100 %
var minHumi = 0;
var maxHumi = 100;
var newVal = scaleValue(curVal, [minHumi, maxHumi], [0, 180]);
$('.gauge--2 .semi-circle--mask').attr({
style: '-webkit-transform: rotate(' + newVal + 'deg);' +
'-moz-transform: rotate(' + newVal + 'deg);' +
'transform: rotate(' + newVal + 'deg);'
});
$("#humi").text(curVal + ' %');
}
function scaleValue(value, from, to) {
var scale = (to[1] - to[0]) / (from[1] - from[0]);
var capped = Math.min(from[1], Math.max(from[0], value)) - from[0];
return ~~(capped * scale + to[0]);
}
</script>
</body>
</html>
View raw code
If you try to access your domain name in the following URL path, you’ll see the following:
https://example.com/esp-weather-station.php
That’s it! If you see that web page with empty values in your browser, it means that everything is ready.
In the next section, you’ll learn how to insert data from your ESP32 or ESP8266 into the database.
If everything is correct, this is what you should see in your Arduino IDE Serial Monitor:
If you open your domain name in this URL path:
https://example.com/esp-weather-station.php
You should see the latest 20 readings stored in your database.
There are two gauges that show the latest temperature and humidity readings, and a timestamp.
Refresh the web page to see the latest readings:
There’s a field where you can type the number of readings to visualize, as well as the number of readings for these statistics: minimum, maximum, and average.
By default, it’s set to 20.
For example, if you type 30 and press the update button, you’ll see that your web page updates and recalculates all the values.
The web page is also mobile responsive, so you can use any device to access it:
You can also go to phpMyAdmin to manage the data stored in your SensorData table.
You can delete it, edit, etc…
This article is Part 2 of a previous tutorial.
You need to complete one of the following tutorials before proceeding:
Control ESP32 GPIOs from Anywhere using Firebase
Control ESP8266 NodeMCU GPIOs from Anywhere using Firebase
Firebase hosts your web app over a global CDN using Firebase Hosting and provides an SSL certificate.
You can access your web app from anywhere using the Firebase-generated domain name.
When you first access the web app, you need to authenticate with an authorized email address and password.
You already set up that user and the authentication method in Part 1.
After authentication, you can access a web app page that shows several buttons to change the GPIO states on the database.
The ESP32 or ESP8266 is listening to database changes.
When you click on the buttons, the GPIO states change on the database, and the ESP updates the states accordingly.
The web app also shows what’s the current state of the GPIOs.
As an example, we’ll control three GPIOs (12, 13, and 14).
As mentioned in the previous tutorial, you can add/remove more GPIOs and boards or control other GPIOs.
Once you’re logged in, you can logout any time.
The next time you’ll access the app you’ll need to login again.
The following screenshot shows what the web page looks like on a computer web browser.
After this, you can also access thefirebaseConfigobject if you go to your Project settings in your Firebase console.
The index.html file contains some HTML text to build a web page.
For now, leave the default HTML text.
The idea is to replace that with your own HTML text to build a custom web page for your needs.
We’ll do that later in this tutorial.
You should get a
The web page you’ve seen previously is built with the HTML file placed in the public folder of your Firebase project.
By changing the content of that file, you can create your own web app.
That’s what we’re going to do in the next section.
| btn1On | btn2On | btn3On | |
| btn1Off | btn2Off | btn3Off | |
| state1 | state2 | state3 |
Then, copy the following to the style.css file
html {
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: inline-block;
text-align: center;
}
h2{
font-size: 1.8rem;
color: white;
}
.topnav {
overflow: hidden;
background-color: #049faa;
color: white;
font-size: 1rem;
padding: 10px;
}
#authentication-bar{
background-color:mintcream;
padding-top: 10px;
padding-bottom: 10px;
}
#user-details{
color: cadetblue;
}
.content {
padding: 20px;
}
body {
margin: 0;
}
.card-grid {
max-width: 800px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
color: #034078
}
.state {
color:#1282A2;
}
button {
background-color: #049faa;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
border-radius: 4px;
}
.button-on {
background-color:#034078;
}
.button-on:hover {
background-color: #1282A2;
}
.button-off {
background-color:#858585;
}
.button-off:hover {
background-color: #252524;
}
.form-elements-container{
padding: 16px;
width: 250px;
margin: 0 auto;
}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
View raw code
The CSS file includes some simple styles to make our webpage look better.
We won’t discuss how CSS works in this tutorial.
You can easily modify the CSS file to change the colors and font size, for example.
Firebase offers a free hosting service to serve your assets and web apps.
Then, you can access your web app from anywhere.
You can use the Hosting URL provided to access your web app from anywhere.
The web app is responsive, and you can access it using your smartphone, computer, or tablet.
Insert the email and password of the authorized user you added in the Firebase Authentication methods.
After that, you can access the dashboard to control the ESP32 or ESP8266 GPIOs.
Go to your project’s Firebase console
Updated on 27 March 2023
This project is also very versatile.
Through your cloud dashboard, you can easily control more outputs (without uploading new code to your board) and you can even connect multiple boards to your server.
Previously, we’ve stored sensor readings into a database and we’ve used different methods to display sensor readings on a:
Table
Charts
Gauges
Now, I’ve created this new project where you can create buttons in a dashboard and assign them to a Board and GPIO number.
Then, you can use the toggle switches to control the ESP32 or ESP8266 outputs from anywhere.
There are many ways of controlling outputs from anywhere, and even though this is a working solution there are other methods that provide a two-way communication with your devices .
I also recommend that you take this project further and add more features to fit your own needs.
To build this project, you’ll use these technologies:
ESP32 or ESP8266 programmed with Arduino IDE
Hosting server and domain name
PHP scripts to store and retrieve the output states stored in a MySQL database
This project is divided into the following main sections:
You have a web page running a PHP script with some toggle buttons that allow you to control the outputs on and off;
When you press the buttons, it updates the output state and saves it in your database;
You can add more buttons or delete them from your dashboard;
Then, you can have an ESP32 or ESP8266 or even multiple boards that make HTTP GET requests every X number of seconds to your server;
Finally, according to the result of that HTTP GET request, the ESP board updates its GPIOs accordingly.
That’s it! Your new database and user were created successfully.
Now, save all your details because you’ll need them later:
In the left sidebar, select your database name example_esp_data and open the “SQL” tab.
After that, you should see your newly created tables called Boards and Outputs in the example_esp_data database as shown in the figure below:
That’s it! You should see that web page with your default button.
The default button is called
After installing the necessary board add-ons and libraries, copy the following code to your Arduino IDE, but don’t upload it yet.
You need to make some changes to make it work for you.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/control-esp32-esp8266-gpios-from-anywhere/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <Arduino_JSON.h>
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
//Your IP address or domain name with URL path
const char* serverName = "https://example.com/esp-outputs-action.php?action=outputs_state&board=1";
// Update interval time set to 5 seconds
const long interval = 5000;
unsigned long previousMillis = 0;
String outputsState;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
}
void loop() {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis >= interval) {
// Check WiFi connection status
if(WiFi.status()== WL_CONNECTED ){
outputsState = httpGETRequest(serverName);
Serial.println(outputsState);
JSONVar myObject = JSON.parse(outputsState);
// JSON.typeof(jsonVar) can be used to get the type of the var
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
return;
}
Serial.print("JSON object = ");
Serial.println(myObject);
// myObject.keys() can be used to get an array of all the keys in the object
JSONVar keys = myObject.keys();
for (int i = 0; i < keys.length(); i++) {
JSONVar value = myObject[keys[i]];
Serial.print("GPIO: ");
Serial.print(keys[i]);
Serial.print(" - SET to: ");
Serial.println(value);
pinMode(atoi(keys[i]), OUTPUT);
digitalWrite(atoi(keys[i]), atoi(value));
}
// save the last HTTP GET Request
previousMillis = currentMillis;
}
else {
Serial.println("WiFi Disconnected");
}
}
}
String httpGETRequest(const char* serverName) {
WiFiClientSecure *client = new WiFiClientSecure;
// set secure client without certificate
client->setInsecure();
HTTPClient https;
// Your IP address with path or Domain name with URL path
https.begin(*client, serverName);
// Send HTTP POST request
int httpResponseCode = https.GET();
String payload = "{}";
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = https.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
https.end();
return payload;
}
View raw code
The request retrieves a JSON object that contains the GPIO number and its state.
In this case, it tells us that GPIO 2 should be LOW {“2″:”0”}.
If you open your domain name in this URL path:
https://example.com/esp-outputs.php
You should see the default button in your Dashboard:
If you press that button on and off, you should be able to control GPIO 2 from your ESP32 – Board #1.
You can add more buttons to your project, type a name (
Create another button for
At any point in time, you can use the delete link to remove buttons from your Dashboard or use the form at the bottom to create more.
Since this is not a two-way communication, when you press the buttons to control your outputs, your board doesn’t update the outputs instantly.
It will take a few seconds for your ESP board to make a new HTTP GET request and update its output states.
With the
Inside the
You should get a similar message on the debugging window.
The files were successfully uploaded to the ESP32 filesystem.

Access the web server in any web browser and all images should be displayed.
Drag and drop your images.
You can upload up to 20 images at the same time.
For this example we’ll be using the following six images.
Then, copy the data from the first field.
That’s what you need to use as source in your <img src=””> HTML tag.
Access the web server in any web browser and all images should be displayed.
If you want to get date and time in a human readable format, we recommend the following tutorial instead:
ESP32 NTP Client-Server: Get Date and Time (Arduino IDE)
There are NTP servers like pool.ntp.org that anyone can use to request time as a client.
In this case, the ESP32 is an NTP Client that requests time from an NTP Server (pool.ntp.org).
This article covers the following topics:
This library needs some other library dependencies.
A new window should pop up asking you to install any missing dependencies.
Select “Install all”.
If this window doesn’t show up, you’ll need to install the following library dependencies:
ArduinoJson (by bblanchon)
TaskScheduler
ESPAsyncTCP (ESP8266)
AsyncTCP (ESP32)
If you’re using PlatformIO , add the following lines to the platformio.ini file to add the libraries and change the monitor speed.
For the ESP32:
monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
ArduinoJson
arduinoUnity
TaskScheduler
AsyncTCP
For the ESP8266:
monitor_speed = 115200
lib_deps = painlessmesh/painlessMesh @ ^1.4.5
ArduinoJson
TaskScheduler
ESPAsyncTCP
You should also see other messages when there are changes on the mesh: when a board leaves or joins the network.
As an example, we’ll exchange sensor readings from a BME280 sensor , but you can use any other sensor.
If you’re using VS Code with PlatformIO, include the libraries in the platformio.ini file as follows:
Recommended reading: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)
Recommended reading: ESP8266 with BME280 using Arduino IDE (Pressure, Temperature, Humidity)
This tutorial is an improvement of the following:
ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)
The new version includes:
Two-way communication between the server and the slaves;
Auto-pairing peers—you don’t need to know any of the boards’ MAC addresses.
You don’t need to add peers manually.
You just need to run the codes provided and the boards will be automatically added to the ESP-NOW network.
The improvements were suggested by one of our readers (
The ESP32/ESP8266 sender boards
There are two ESP sender boards (ESP32 or ESP8266) that send readings
The peer sends a message of type PAIRING to the server (
You can access the web server on the board’s IP address.
At the moment, there won’t be any data displayed because we haven’t prepared the sender boards yet.
Let the server board run the code.
As you can see, first, it sends a pairing request using different channels until it gets a response from the server.
In this case, it is using channel 6.
After that, we start receiving messages from the server.
We also send messages to the server.
On the server side, this is what happens:
The server receives a pairing request from the sender.
It will pair with the sender.
In my case, it was already paired because I had run this code before.
After data, we start sending and receiving data.
You can upload the sender code to multiple boards and they will all automatically pair with the server.
The sender boards can be ESP32 or ESP8266 boards.
Make sure you use the right code for the board you’re using.
Now, you can go to the server’s IP address to see the readings from the sender boards displayed on the dashboard.
The web page is prepared to display readings from two boards.
If you want to display more readings you need to modify the web page.
We have other tutorials for ESP-NOW with the ESP32:
ESP-NOW Two-Way Communication Between ESP32 Boards
ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)
ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)
ESP32: ESP-NOW Web Server Sensor Dashboard (ESP-NOW + Wi-Fi)
In summary, ESP-NOW is ideal to build a network in which you can have several ESP32 boards exchanging data with each other.
Save your board MAC address because you’ll need it to send data to the right board via ESP-NOW.
We’ll send a structure that contains a variable of type char, int, float, and boolean.
Then, you can modify the structure to send whichever variable types are suitable for your project (like sensor readings, or boolean variables to turn something on or off).
For better understanding, we’ll call “sender” to ESP32 #1 and “receiver” to ESP32 #2.
Here’s what we should include in the sender sketch:
Initialize ESP-NOW;
Register a callback function upon sending data – the OnDataSent function will be executed when a message is sent.
This can tell us if the message was successfully delivered or not;
Add a peer device (the receiver).
For this, you need to know the receiver MAC address;
Send a message to the peer device.
On the receiver side, the sketch should include:
Initialize ESP-NOW;
Register for a receive callback function (OnDataRecv).
This is a function that will be executed when a message is received.
Inside that callback function, save the message into a variable to execute any task with that information.
ESP-NOW works with callback functions that are called when a device receives a message or when a message is sent (you get if the message was successfully delivered or if it failed).
| esp_now_init() Initializes ESP-NOW. You must initialize Wi-Fi before initializing ESP-NOW. |
| esp_now_add_peer() Call this function to pair a device and pass as an argument the peer MAC address. |
| esp_now_send() Send data with ESP-NOW. |
| esp_now_register_send_cb() Register a callback function that is triggered upon sending data. When a message is sent, a function is called – this function returns whether the delivery was successful or not. |
| esp_now_register_rcv_cb() Register a callback function that is triggered upon receiving data. When data is received via ESP-NOW, a function is called. |
And this is what you should get on the receiver side.
Note that the Int variable changes between each reading received (because we set it to a random number on the sender side).
We tested the communication range between the two boards, and we are able to get a stable communication up to 220 meters (approximately 722 feet) in open field.
In this experiment both ESP32 on-board antennas were pointing to each other.
We have other guides related with ESP-NOW that you might be interested in:
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
ESP-NOW Two-Way Communication Between ESP32 Boards
ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)
One ESP32 board acts as a receiver/slave;
Multiple ESP32 boards act as senders/masters.
We’ve tested this example with 5 ESP32 sender boards and it worked fine.
You should be able to add more boards to your setup;
The sender board receives an acknowledge message indicating if the message was successfully delivered or not;
The ESP32 receiver board receives the messages from all senders and identifies which board sent the message;
As an example, we’ll exchange random values between the boards.
You should modify this example to send commands or sensor readings ( exchange sensor readings using ESP-NOW ).
Upload the following code to each of your sender boards.
Don’t forget to increment the id number for each sender board.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-many-to-one-esp32/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
#include <esp_now.h>
#include <WiFi.h>
// REPLACE WITH THE RECEIVER'S MAC Address
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
int id; // must be unique for each sender board
int x;
int y;
} struct_message;
// Create a struct_message called myData
struct_message myData;
// Create peer interface
esp_now_peer_info_t peerInfo;
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
// Init Serial Monitor
Serial.begin(115200);
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
}
void loop() {
// Set values to send
myData.id = 1;
myData.x = random(0,50);
myData.y = random(0,50);
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
delay(10000);
}
View raw code
On the receiver board, you should be receiving the packets from all the other boards.
In this test, we were receiving data from 5 different boards.
To get started with ESP-NOW on the ESP32 or ESP8266, read the following ESP-NOW guides first:
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
Getting Started with ESP-NOW (ESP8266 NodeMCU with Arduino IDE)
ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)
One ESP32 acts as a sender;
Multiple ESP32 or ESP8266 boards act as receivers.
We tested this setup with two ESP32 boards and one ESP8266 board simultaneously.
You should be able to add more boards to your setup;
The ESP32 sender receives an acknowledge message if the messages are successfully delivered.
You know which boards received the message and which boards didn’t;
You need to upload a slightly different receiver code depending if you’re using an ESP32 or ESP8266;
As an example, we’ll exchange random values between the boards.
You should modify this example to send commands or sensor readings ( exchange sensor readings using ESP-NOW ).
This tutorial covers these two scenarios:
sending the same message to all boards;
sending a different message to each board.
You may also like reading: ESP-NOW Two-Way Communication Between ESP32 Boards .
You can write down the boards’ MAC address on a label to clearly identify each board.
If you remove power from one of the boards, you’ll receive a “
If you want to check if the boards are actually receiving the messages, you can open the Serial Monitor for the COM port they are connected to, or you can use PuTTY to establish a serial communication with your boards.
If you’re using PuTTY, select Serial communication, write the COM port number and the baud rate (115200) as shown below and click
Then, you should see the messages being received.
Open a serial communication for each of your boards and check that they are receiving the messages.
In this project we’ll have two ESP32 boards.
Each board is connected to an OLED display and a BME280 sensor;
Each board gets temperature, humidity and pressure readings from their corresponding sensors;
Each board sends its readings to the other board via ESP-NOW;
When a board receives the readings, it displays them on the OLED display;
After sending the readings, the board displays on the OLED if the message was successfully delivered;
Each board needs to know the other board MAC address in order to send the message.
In this example, we’re using a two-way communication between two boards, but you can add more boards to this setup, and having all boards communicating with each other.
Write down the MAC address of each board to clearly identify them.
You can use the following table as a reference when wiring the BME280 sensor.
| VIN | 3.3V |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
| GND | GND |
| VCC | VIN |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
As you can see, it’s working as expected:
We tested the communication range between the two boards, and we are able to get a stable communication up to 220 meters (approximately 722 feet) in open field.
In this experiment both ESP32 on-board antennas were pointing to each other.
In most projects with the ESP32, we connect the ESP32 to a wireless router (see our ESP32 web server tutorial ).
This way we can access the ESP32 through the local network.
In this situation the router acts as an access point and the ESP32 is set as a station.
In this scenario, you need to be connected to your router (local network) to control the ESP32.
But if you set the ESP32 as an access point (hotspot), you can be connected to the ESP32 using any device with Wi-Fi capabilities without the need to connect to your router.
In simple words, when you set the ESP32 as an access point you create its own Wi-Fi network and nearby Wi-Fi devices (stations) can connect to it (like your smartphone or your computer).
Here we’ll show you how to set the ESP32 as an access point in your web server projects.
This way, you don’t need to be connected to a router to control your ESP32.
Because the ESP32 doesn’t connect further to a wired network (like your router), it is called soft-AP (soft Access Point).
ESP32 development board – read ESP32 Development Boards Review and Comparison
2x 5mm LED
2x 330 Ohm resistor
Breadboard
Jumper wires
Enter the password you’ve defined earlier in the code.
Open your web browser and type the IP address 192.168.4.1.
The web server page should load:
To connect to the access point on your computer, go to the Network and Internet Settings and select the “
Insert the password you’ve defined earlier.
And it’s done! Now, to access the ESP32 web server page, you just need to type the ESP32 IP address on your browser.
Reading analog inputs with the ESP32 is as easy as using the analogRead(GPIO) function, that accepts as argument, the GPIO you want to read.
We also have other tutorials on how to use analog pins with ESP board:
ESP8266 ADC – Read Analog Values with Arduino IDE, MicroPython and Lua
ESP32 Analog Readings with MicroPython

Learn more about the ESP32 GPIOs: ESP32 Pinout Reference .
These analog input pins have 12-bit resolution.
This means that when you read an analog input, its range may vary from 0 to 4095.
The maximum value you’ll get is 4095 and the minimum value is 0.
The web server contains one heading “ESP Web Server” and three buttons (toggle switches) to control three outputs.
Each slider button has a label indicating the GPIO output pin.
You can easily remove/add more outputs.
When the slider is red, it means the output is on (its state is HIGH).
If you toggle the slider, it turns off the output (change the state to LOW).
When the slider is gray, it means the output is off (its state is LOW).
If you toggle the slider, it turns on the output (change the state to HIGH).
Let’s see what happens when you toggle the buttons.
We’ll see the example for GPIO 2.
It works similarly for the other buttons.
The following <meta> tag makes your web page responsive in any browser (laptop, tablet or smartphone).
<meta name="viewport" content="width=device-width, initial-scale=1">
If we don’t add the following line, the ESP32 will receive a request for the favicon every time we access the web server.
<link rel="icon" href="data:,">
Between the <style></style>tags, we add some CSS to style the web page.
We won’t go into detail on how this CSS styling works.
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
p {font-size: 3.0rem;}
body {max-width: 600px; margin:0px auto; padding-bottom: 25px;}
.switch {position: relative; display: inline-block; width: 120px; height: 68px}
.switch input {display: none}
.slider {position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; border-radius: 6px}
.slider:before {position: absolute; content: ""; height: 52px; width: 52px; left: 8px; bottom: 8px; background-color: #fff; -webkit-transition: .4s; transition: .4s; border-radius: 3px}
input:checked+.slider {background-color: #b30000}
input:checked+.slider:before {-webkit-transform: translateX(52px); -ms-transform: translateX(52px); transform: translateX(52px)}
</style>
Press the toggle buttons to control the ESP32 GPIOs.
At the same time, you should get the following messages in the Serial Monitor to help you debug your code.
You can also access the web server from a browser in your smartphone.
Whenever you open the web server, it shows the current GPIO states.
Red indicates the GPIO is on, and gray that the GPIO is off.
You’ll learn how to wire the sensor to the ESP32 board, install the required libraries and use a simple sketch to display the sensor readings in the Serial Monitor.
This tutorial covers the following topics:
| 4 lux precision | 16 ms measurement time | |
| 1 lux precision | 120 ms measurement time | |
| 0.5 lux precision | 120 ms measurement time |
The BH1750 is an ambient light sensor so it can be used in a wide variety of projects.
For example:
to detect if it is day or night;
to adjust or turn on/off LED’s brightness accordingly to ambient light;
to adjust LCDs and screen’s brightness;
to detect if an LED is lit;
…
Here’s the BH1750 Pinout:
| Powers the sensor (3.3V or 5V) | |
| Common GND | |
| SCL pin for I2C communication | |
|
| SDA pin for I2C communication |
|
| Selects address |
You can connect the BH1750 sensor to the ESP32 using the default’s I2C pins:
| SCL | GPIO 22 |
| SDA | GPIO 21 |
You can also follow the next table:
| 3.3V | |
| GND | |
| GPIO 22 | |
|
| GPIO 21 |
|
| Don’t connect |
After successfully uploading the code, open the Serial Monitor at a baud rate of 9600 and press the ESP32 on-board RST button.
New luminance readings should be printed in the Serial Monitor.
There are other possible communication modes like broadcast mode and mesh network (not covered in this tutorial).
The ESP32 BLE server is connected to a BME280 sensor and it updates its temperature and humidity characteristic values every 30 seconds.
The ESP32 client connects to the BLE server and it is notified of its temperature and humidity characteristic values.
This ESP32 is connected to an OLED display and it prints the latest readings.
This project is divided into two parts:
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Then, you can test if the BLE server is working as expected by using a BLE scan application on your smartphone like
Connect to your BME280_ESP32 device and then, select the client tab (the interface might be slightly different).
You can check that it advertises the service with the UUID we defined in the code, as well as the temperature and humidity characteristics.
Notice that those characteristics have the Notify property.
Your ESP32 BLE Server is ready!
Go to the next section to create an ESP32 client that connects to the server to get access to the temperature and humidity characteristics and get the readings to display them on an OLED display.
Bluetooth Low Energy, BLE for short, is a power-conserving variant of Bluetooth.
BLE’s primary application is short-distance transmission of small amounts of data (low bandwidth).
Unlike Bluetooth which is always on, BLE remains in sleep mode constantly except for when a connection is initiated.
This makes it consume very little power.
BLE consumes approximately 100x less power than Bluetooth (depending on the use case).
You can check the main differences between Bluetooth and Bluetooth Low Energy here .
We’re going to use the default UUIDs for the Environmental Sensing Profile and corresponding characteristics.
If you go to this page and open the Assigned Numbers Document (PDF) , you’ll find all the default assigned UUID numbers.
If you search for the Environmental Sensing Service, you’ll find all the permitted characteristics that you can use with that service.
You can see that it supports, temperature, humidity, and pressure.
There’s a table with the UUIDs for all services.
You can see that the UUID for the Environmental Sensing service is
Then, search for the temperature, humidity, and pressure characteristics UUIDs.
You’ll find a table with the values for all characteristics.
The UUIDs for the temperature, humidity, and pressure are:
pressure:
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
This means everything is working as expected and the ESP32 is waiting for a BLE client to connect.
Then, go to your smartphone, open the nRF Connect app from Nordic, and start scanning for new devices.
You should find a device called
Connect to it.
You’ll see that it displays the Environmental Sensing service with the temperature, humidity, and pressure characteristics.
Click on the arrows to activate the notifications.
Then, click on the second icon at the left to change the format.
You can change to unsigned int for all characteristics.
You’ll start seeing the temperature, humidity, and pressure values being reported every 10 seconds.
You should also get the readings on the Serial Monitor.
Congratulations! You’ve successfully created an ESP32 BLE Peripheral that advertises the Environmental Sensing Service.
Now, you can develop an app, or program another ESP32 to interface with the ESP32 BLE device.
In this tutorial, we’ll cover the following topics:
Bluetooth is a wireless technology that enables devices to communicate over short distances.
It’s commonly used for connecting devices like headphones to phones or linking a keyboard or mouse to a computer.
The ESP32 board also supports Bluetooth along with Wi-Fi, making it an excellent choice for IoT projects.
This capability allows ESP32-based projects to wirelessly exchange data or connect to other Bluetooth-enabled devices seamlessly.
This variant of Bluetooth is also referred to as “Bluetooth Classic” or simply “Bluetooth”.
Bluetooth Low Energy, BLE for short (also called Bluetooth Smart), is a power-conserving variant of Bluetooth.
BLE’s primary application is short-distance transmission of small amounts of data (low bandwidth).
Unlike Bluetooth which is always on, BLE remains in sleep mode constantly except for when a connection is initiated.
This makes it consume very little power.
BLE consumes approximately 100x less power than Bluetooth (depending on the use case).
| Higher power consumption | Low power consumption | |
| Higher data transfer rates | Lower data transfer rates | |
| Longer range | Shorter range | |
| Audio streaming, file transfer | IoT devices, wearables, smart home | |
| Serial Port Profile (SPP) | Generic Attribute Profile (GATT) |
We have a detailed tutorial explaining how to exchange data with the ESP32 via Bluetooth Classic.
Check the link below:
ESP32 Bluetooth Classic with Arduino IDE – Getting Started (only compatible with Android Smartphones)
It also includes a sample project showing how to send sensor readings to your smartphone and control an LED via Bluetooth Classic.
We have a tutorial explaining how to set one ESP32 board as a client and another as a server to exchange data.
Check the tutorial below:
ESP32 BLE Server and Client (Bluetooth Low Energy)
In this project, we show how to send sensor data from one ESP32 board to another via BLE.
The receiver board displays the data on an OLED display.
We have a tutorial explaining how to set the ESP32 as a Bluetooth device that exposes an environmental sensing device following the default GATT structure and UUIDs.
ESP32 BLE Peripheral (Server): Environmental Sensing Service
This is a great project to better understand how the GATT structure works and how to properly create BLE devices with the ESP32.
This cross-platform compatibility removes the need for users to download and install dedicated mobile apps, simplifying the user experience and reducing development efforts.
We have an in-depth tutorial explaining the principles of Web Bluetooth and how to create a Web Bluetooth App to exchange data with the ESP32 to get sensor readings and control outputs.
Check the tutorial below:
ESP32 Web Bluetooth (BLE): Getting Started Guide
Additionally, BLE supports not only point-to-point communication, but also broadcast mode, and mesh network.
Take a look at the table below that compares BLE and Bluetooth Classic in more detail.
View Image Souce
Due to its properties, BLE is suitablefor applications that need to exchange small amounts of data periodically running on a coin cell.
For example, BLE is of great use in healthcare, fitness, tracking, beacons, security, and home automation industries.
As mentioned previously, BLE also supports broadcast mode and mesh network:
View Image Souce
Go to the Serial Monitor with the ESP32 running the “BLE_scan” example, press the ESP32 (with the “BLE_scan” sketch) ENABLE button to restart and wait a few seconds while it scans.
The scanner found two devices: one is the ESP32 (it has the name “
Click the “
The characteristic has the READ and WRITE properties, and the value is the one you’ve previously defined in the BLE server sketch.
So, everything is working fine.
We’ll show you how to wire the sensor to the ESP32, install the required libraries, and write a simple sketch that displays the sensor readings.
This sensor communicates using I2C communication protocol, so the wiring is very simple.
You can use the default ESP32 I2C pins as shown in the following table:
| Vin | 3.3V |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
If you’re using one of these sensors, to use I2C communication protocol, use the following pins:
| SCK (SCL Pin) | GPIO 22 |
| SDI (SDA pin) | GPIO 21 |
| SCK (SPI Clock) | GPIO 18 |
| SDO(MISO) | GPIO 19 |
| SDI (MOSI) | GPIO 23 |
| CS (Chip Select) | GPIO 5 |
After installing the libraries, restart your Arduino IDE.
After installing the BME280 library, and the Adafruit_Sensor library, open the Arduino IDE and, go to | HSPI | GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
| VSPI | GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 |
You’ll learn how to wire the sensor to the ESP32 board, install the required libraries, use a simple sketch to display the sensor readings in the Serial Monitor and build a web server to monitor your sensor remotely.
| Temperature | +/- 1.0oC |
| Humidity | +/- 3% |
| Pressure | +/- 1 hPa |
|
| |
| Temperature | -40 to 85 oC |
| Humidity | 0 to 100 % |
| Pressure | 300 to 1100 hPa |
| Powers the sensor | |
| Common GND | |
| SCL pin for I2C communication SCK pin for SPI communication | |
| SDA pin for I2C communication SDI (MOSI) pin for SPI communication | |
| SDO (MISO) pin for SPI communication | |
| Chip select pin for SPI communication |
| SCL | GPIO22 |
| SDA | GPIO 21 |
| SCL (SCK SPI Clock) | GPIO 18 |
| SDA (SDI MOSI) | GPIO 23 |
| SDO (MISO) | GPIO 19 |
| CS (Chip Select) | GPIO 5 |
To complete this tutorial you need the following parts:
BME680 sensor module
ESP32 (read Best ESP32 development boards )
Breadboard
Jumper wires
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
After installing the libraries, restart your Arduino IDE.
The readings are updated automatically on the web server using Server-Sent Events.
We won’t explain how the web server works in this tutorial.
We wrote this guide dedicated to the BME680 web server with the ESP32 board.
To build the web server we’ll use theESP Async Web Server librarythat provides an easy way to build an asynchronous web server.
The BME680 contains a MOX (Metal-oxide) sensor that detects VOCs in the air.
This sensor gives you a qualitative idea of the
To complete this tutorial you need the following parts:
BME680 sensor module
ESP32 (read Best ESP32 development boards )
Breadboard
Jumper wires
Recommended reading: ESP32 Pinout Reference – Which GPIO pins should you use?
The readings are updated automatically using Server-Sent Events.
In this tutorial, we cover:
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU with BMP388 Barometric/Altimeter Sensor (Arduino)
The following picture shows the other side of the sensor.
| 300 to 1250 hPa (pressure) -40 to +85oC (temperature) | |
| I2C and SPI | |
| 3.4 μA @ 1Hz | |
|
P=900 …1100 hPa (T=25 … 40°C) | ±0.5 hPa |
|
P=900…1100 hPa (T=25 … 40°C) | ±0.08 hPa |
|
| 0.03 Pa |
| 200 Hz |
| VIN | Powers the sensor (5V) |
| 3V3 | Powers the sensor (3V3) |
| GND | Common GND |
| SCK | SCL pin for I2C communication SCK pin for SPI communication |
| SDO | SDO (MISO) pin for SPI communication |
| SDI | SDI (MOSI) pin for SPI communication SDA pin for I2C communication |
| CS | Chip select pin for SPI communication |
| INT | Interrupt pin |
|
| GPIO 21 |
|
| GPIO 22 |
| GPIO 18 | |
|
| GPIO 23 |
|
| GPIO 19 |
|
| GPIO 5 |
To complete this tutorial you need the following parts:
BMP388 sensor module
ESP32 (read Best ESP32 development boards )
Breadboard
Jumper wires
After installing the libraries, restart your Arduino IDE.
Notice that if you increase the sensor’s altitude, it will be reflected in the altitude reading.
The altitude estimation is pretty accurate.
It can detect small changes in the centimeters or inches range.
You can check it by comparing the altitude you’re getting with the altitude of your location.
To get your location’s altitude, you can use this website .
The readings are updated automatically on the web server using Server-Sent Events.
You can check the Server-Sent Events tutorial to have an idea of how it works.
As a regular ESP32 board, it features a BOOT and a EN (RST) button.
Some models have the buttons at the back, some have both at the front, and others have one at the front and other at the back.
However, all boards should work in a similar way.

| GPIO 5 | |
| GPIO 4 |
3.
After installing the SSD1306 library from Adafruit, type “
4.
After installing the libraries, restart your Arduino IDE.
If you look closely, you should have a jumper on the 3.3V pads.
If you want to have an output of 5V on the VCC pin, you need to unsolder that connection and solder the 5V pads.
| CLK | GPIO 14 |
| CMD | GPIO 15 |
| DATA0 | GPIO 2 |
| DATA1 / flashlight | GPIO 4 |
| DATA2 | GPIO 12 |
| DATA3 | GPIO 13 |
Next to the RST button, there’s an on-board red LED.
That LED is internally connected to GPIO 33.
You can use this LED to indicate that something is happening.
For example, if the Wi-Fi is connected, the LED is red or vice-versa.
That LED works with inverted logic, so you send a LOW signal to turn it on and a HIGH signal to turn it off.
You can experiment uploading the following snippet and see if you get that LED glowing.
void setup() {
pinMode(33, OUTPUT);
}
void loop() {
digitalWrite(33, LOW);
}
| D0 | GPIO 5 | Y2_GPIO_NUM |
| D1 | GPIO 18 | Y3_GPIO_NUM |
| D2 | GPIO 19 | Y4_GPIO_NUM |
| D3 | GPIO 21 | Y5_GPIO_NUM |
| D4 | GPIO 36 | Y6_GPIO_NUM |
| D5 | GPIO 39 | Y7_GPIO_NUM |
| D6 | GPIO 34 | Y8_GPIO_NUM |
| D7 | GPIO 35 | Y9_GPIO_NUM |
| XCLK | GPIO 0 | XCLK_GPIO_NUM |
| PCLK | GPIO 22 | PCLK_GPIO_NUM |
| VSYNC | GPIO 25 | VSYNC_GPIO_NUM |
| HREF | GPIO 23 | HREF_GPIO_NUM |
| SDA | GPIO 26 | SIOD_GPIO_NUM |
| SCL | GPIO 27 | SIOC_GPIO_NUM |
| POWER PIN | GPIO 32 | PWDN_GPIO_NUM |
This guide covers the pin/GPIOs assignment for the following ESP32 Camera Development boards:
For a detailed comparison of the different ESP32 Camera Boards, read:
ESP32 Camera Dev Boards Review and Comparison (Best ESP32-CAM)
This is the OV2640 camera pin assignment for the ESP32-CAM AI-Thinker board:
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
The ESP32-CAM AI-Thinker comes with 10 exposed GPIOs.
Learn how to use those GPIOs with this ESP32-CAM Pinout Reference Guide .
Pin definition for the ESP32-Wrover CAM board (Freenove brand).
In some of the examples, this pin definition is under the CAMERA_MODEL_WROVER_KIT.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
Pin assignment for the TTGO T-Journal board.
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
Pin assignment for the M5-Camera Model A.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
Pin assignment for the M5-Camera Model B.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 22
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
Pin assignment for the M5-stack ESP32 camera without PSRAM.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
Pin assignment for the ESP-EYE camera.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
Pin assignment for the TTGO T-Camera Plus.
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 26
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
Pin definition for the T-Camera with PIR sensor (without microphone and without BME280):
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 32
#define SIOD_GPIO_NUM 13
#define SIOC_GPIO_NUM 12
#define Y9_GPIO_NUM 39
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 23
#define Y6_GPIO_NUM 18
#define Y5_GPIO_NUM 15
#define Y4_GPIO_NUM 4
#define Y3_GPIO_NUM 14
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 27
#define HREF_GPIO_NUM 25
#define PCLK_GPIO_NUM 19
The robot moves as long as you’re pressing the buttons.
When you release any button, the robot stops.
However, we’ve included the
We won’t explain how the L298N motor driver works.
You can read the following article for an in-depth tutorial about the L298N motor driver:
ESP32 with DC Motor and L298N Motor Driver – Control Speed and Direction
Open a browser and type the ESP IP address.
A similar web page should load:
Press the buttons and take a look at the Serial Monitor to see if it is streaming without lag and if it is receiving the commands without crashing.
If everything is working properly, it’s time to assemble the circuit.
Start by connecting the ESP32-CAM to the motor driver as shown in the schematic diagram.
You can either use a mini breadboard or a stripboard to place your ESP32-CAM and build the circuit.
The following table shows the connections between the ESP32-CAM and the L298N Motor Driver.
| IN1 | GPIO 14 |
| IN2 | GPIO 15 |
| IN3 | GPIO 13 |
| IN4 | GPIO 12 |
After that, wire each motor to its terminal block.
Don’t forget that you should use an external antenna with the ESP32-CAM, otherwise the web server might be extremely slow.
Next to the IPEX connector there are three little white squares laid out like a “
Take a look at your board to see if it is set to use the on-board antenna or the IPEX connector.
Using the on-board antenna works well if you are close to your router.
We recommend using the IPEX connector with an external antenna for better results.
Projects with video streaming crash frequently when you don’t use an external antenna due to poor connectivity.
So, make sure you get one to have your projects working reliably.
To enable or disable the on-board antenna, you just need to unsolder that resistor and solder it in the desired configuration.
You can also drop some solder to connect those points (you don’t necessarily need to add the resistor as long as the pads are connected).
The instructions in this tutorial work for any ESP32 camera development board as long as it comes with the OV2640 camera.
In this tutorial we’ll show you how to implement those changes on your code regardless of the project you’re building: taking photos or streaming video.
We recommend that you follow the Camera Web Server project first and play with the image settings to see what each setting does:
ESP32-CAM Video Streaming and Face Recognition with Arduino IDE
Depending on where your camera is located, you may want to change some settings to get a better picture.
Playing with that web server gives you an idea of what you need to change and what values you need to set to get a better picture.
Once you know the best settings for your camera, you may want to apply them in your other projects.
| set_brightness() | Set brightness | -2 to 2 |
| set_contrast() | Set contrast | -2 to 2 |
| set_saturation() | Set saturation | -2 to 2 |
| set_special_effect() | Set a special effect | 0 – No Effect 1 – Negative 2 – Grayscale 3 – Red Tint 4 – Green Tint 5 – Blue Tint 6 – Sepia |
| set_whitebal() | Set white balance | 0 – disable 1 – enable |
| set_awb_gain() | Set white balance gain | 0 – disable 1 – enable |
| set_wb_mode() | Set white balance mode | 0 – Auto 1 – Sunny 2 – Cloudy 3 – Office 4 – Home |
| set_exposure_ctrl() | Set exposure control | 0 – disable 1 – enable |
| set_aec2() | 0 – disable 1 – enable | |
| set_ae_level() | -2 to 2 | |
| set_aec_value() | 0 to 1200 | |
| set_gain_ctrl() | 0 – disable 1 – enable | |
| set_agc_gain() | 0 to 30 | |
| set_gainceiling() | 0 to 6 | |
| set_bpc() | 0 – disable 1 – enable | |
| set_wpc() | 0 – disable 1 – enable | |
| set_raw_gma() | 0 – disable 1 – enable | |
| set_lenc() | Set lens correction | 0 – disable 1 – enable |
| set_hmirror() | Horizontal mirror | 0 – disable 1 – enable |
| set_vflip() | Vertical flip | 0 – disable 1 – enable |
| set_dcw() | 0 – disable 1 – enable | |
| set_colorbar() | Set a colorbar | 0 – disable 1 – enable |




This project is very similar with a previous one , but after so many requests, we added a PIR motion sensor to the circuit.
So, when motion is detected a picture is taken and saved on the microSD card.
Other ESP32-CAM projects and tutorials:
ESP32-CAM Video Streaming and Face Recognition with Arduino IDE
ESP32-CAM Video Streaming Web Server (Home Assistant, Node-RED, etc…)
ESP32-CAM Take Photo and Save to MicroSD Card
Take Photo, Save to SPIFFS and Display in Web Server
ESP32-CAM Troubleshooting Guide
We have a similar project using a Raspberry Pi and a camera module:
Raspberry Pi Motion Detector with Photo Capture
Here is a quick overview on how the project works.
The ESP32-CAM is in deep sleep mode with external wake up enabled.
When motion is detected, the PIR motion sensor sends a signal to wake up the ESP32.
The ESP32-CAM takes a photo and saves it on the microSD card.
It goes back to deep sleep mode until a new signal from the PIR motion sensor is received.
Many FTDI programmers have a jumper that allows you to select 3.3V or 5V.
Make sure the jumper is in the right place to select 5V.
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
Assemble all the parts as shown in the following schematic diagram.

To prevent problems during upload, we recommend assembling the circuit only after uploading the code.
Then, press the reset (RST) button, and it should start working.
When it detects motion, it turns on the flash, takes a photo and saves it on the microSD card.
Experiment with this circuit several times to make sure that it is working.
Then, insert the microSD card to your computer to see the captured photos.
Here’s an example:
Now you can finish this project the way you want, you can either use a dummy camera and insert your ESP32-CAM with the PIR motion sensor, or you can build your own enclosure.
You can also apply the concepts learned in this tutorial in your own projects.
Updated on 27 March 2023
To build this project, you need to follow the next steps.
Follow the LAMP Server or the Hosting Server instructions depending on if you want to access the photos locally or from anywhere.
Hosting your PHP Application
PHP scripts to save and display photos in the server
You can run a LAMP (Linux, Apache, MySQL, PHP) server on a Raspberry Pi to access data in your local network .
Raspberry Pi LAMP Server: Local Linux server that you use to access your images locally.
Setup Local RPi LAMP Server
Bluehost (user-friendly with cPanel) : free domain name when you sign up for the 3-year plan.
I recommend choosing the unlimited websites option; Note that any hosting service that offers PHP will work with this tutorial.
If you don’t have a hosting account, I recommend signing up for Bluehost .
Get Hosting and Domain Name with Bluehost
When buying a hosting account, you’ll also have to purchase a domain name.
This is what makes this project interesting: you’ll be able to go your domain name (http://example.com) and see your ESP32-CAM photos.
If you like our projects, you might consider signing up to Bluehost, because you’ll be supporting our work.
Then, create a new gallery.php file:
pi@raspberrypi:/var/www/html $ nano gallery.php
Edit the newly created file (gallery.php) and copy the following snippet:
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<!DOCTYPE html>
<html>
<head>
<title>ESP32-CAM Photo Gallery</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-container > div {
text-align: center;
margin: 10px;
}
</style>
</head><body>
<h2>ESP32-CAM Photo Gallery</h2>
<?php
// Image extensions
$image_extensions = array("png","jpg","jpeg","gif");
// Check delete HTTP GET request - remove images
if(isset($_GET["delete"])){
$imageFileType = strtolower(pathinfo($_GET["delete"],PATHINFO_EXTENSION));
if (file_exists($_GET["delete"]) && ($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg") ) {
echo "File found and deleted: " .
$_GET["delete"];
unlink($_GET["delete"]);
}
else {
echo 'File not found - <a href="gallery.php">refresh</a>';
}
}
// Target directory
$dir = 'uploads/';
if (is_dir($dir)){
echo '<div>';
$count = 1;
$files = scandir($dir);
rsort($files);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {?>
<div>
<p><a href="gallery.php?delete=<?php echo $dir .
$file; ?>">Delete file</a> - <?php echo $file; ?></p>
<a href="<?php echo $dir .
$file; ?>">
<img src="<?php echo $dir .
$file; ?>" title=""/>
</a>
</div>
<?php
$count++;
}
}
}
if($count==1) { echo "<p>No images found</p>"; }
?>
</div>
</body>
</html>
View raw code
This PHP script is responsible for displaying the images on the gallery.
Your gallery.php file should look like this.
Save your file and exit (Ctrl+X, Y, and Enter key):
Then, select the
With the three items created, edit the upload.php file:
This PHP script is responsible for receiving incoming images from the ESP32-CAM, rename the images with a timestamp and store them in the uploads folder.
Edit the newly created file (upload.php) and copy the following snippet:
<?php
// Rui Santos
// Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/
// Code Based on this example: w3schools.com/php/php_file_upload.asp
$target_dir = "uploads/";
$datum = mktime(date('H')+0, date('i'), date('s'), date('m'), date('d'), date('y'));
$target_file = $target_dir .
date('Y.m.d_H:i:s_', $datum) .
basename($_FILES["imageFile"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["imageFile"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " .
$check["mime"] .
".";
$uploadOk = 1;
}
else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["imageFile"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
}
else {
if (move_uploaded_file($_FILES["imageFile"]["tmp_name"], $target_file)) {
echo "The file ".
basename( $_FILES["imageFile"]["name"]).
" has been uploaded.";
}
else {
echo "Sorry, there was an error uploading your file.";
}
}
?>
View raw code
Save your file and exit.
Then, edit the gallery.php file and copy the following snippet.
This is responsible for displaying the images in the gallery.
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-cam-post-image-photo-server/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<!DOCTYPE html>
<html>
<head>
<title>ESP32-CAM Photo Gallery</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.flex-container {
display: flex;
flex-wrap: wrap;
}
.flex-container > div {
text-align: center;
margin: 10px;
}
</style>
</head><body>
<h2>ESP32-CAM Photo Gallery</h2>
<?php
// Image extensions
$image_extensions = array("png","jpg","jpeg","gif");
// Check delete HTTP GET request - remove images
if(isset($_GET["delete"])){
$imageFileType = strtolower(pathinfo($_GET["delete"],PATHINFO_EXTENSION));
if (file_exists($_GET["delete"]) && ($imageFileType == "jpg" || $imageFileType == "png" || $imageFileType == "jpeg") ) {
echo "File found and deleted: " .
$_GET["delete"];
unlink($_GET["delete"]);
}
else {
echo 'File not found - <a href="gallery.php">refresh</a>';
}
}
// Target directory
$dir = 'uploads/';
if (is_dir($dir)){
echo '<div>';
$count = 1;
$files = scandir($dir);
rsort($files);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {?>
<div>
<p><a href="gallery.php?delete=<?php echo $dir .
$file; ?>">Delete file</a> - <?php echo $file; ?></p>
<a href="<?php echo $dir .
$file; ?>">
<img src="<?php echo $dir .
$file; ?>" title=""/>
</a>
</div>
<?php
$count++;
}
}
}
if($count==1) { echo "<p>No images found</p>"; }
?>
</div>
</body>
</html>
View raw code
Save your file and exit.
That’s it! Your server is ready.
If you see that message save your URL/domain name and path, your server should be ready and you can continue with this guide.
Additionally, try to access the
Many FTDI programmers have a jumper that allows you to select 3.3V or 5V.
Make sure the jumper is in the right place to select 5V.
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
After a few seconds, the code should be successfully uploaded to your board.
If you have troubles uploading the code, read our ESP32-CAM Troubleshooting Guide .
If you go to your local server URL http://IP-Address/uploads, or to your cloud server URL https://example.com/uploads you should have a folder with all your stored photos.
You can open each link to open a new page with the full image:
Now, if you go to your local server URL http://IP-Address/gallery.php, or to your cloud server URL https://example.com/gallery.php, you can access the gallery page, where you can view and delete the photos.
To delete any photo, just click on the “Delete file” link next to each image.
Updated 19 September 2023.
Firebase is Google’s mobile application development platform that helps you build, improve, and grow your app.
It has many services used to manage data from any Android, IOS, or web application like authentication , realtime database , hosting , storage, etc.
When the ESP32 first runs, it takes a new picture and saves it in the filesystem (LittleFS);
The ESP32-CAM connects to Firebase as a user with email and password;
The ESP32-CAM sends the picture to Firebase Storage;
After that, you can go to your Firebase console to view the pictures;
Later, you can build a web app that you can access from anywhere to display the ESP32-CAM pictures (we’ll create this in a future tutorial).
Notice that Firebase creates a unique UID for each registered user.
The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database.
There’s also a column that registers the date of the last sign-in.
At the moment, it is empty because we haven’t signed in with that user yet.
Change your database rules.
Use the following rules:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth !=null;
}
}
}
When you’re done, click
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
Now, you’re all set to start programming the ESP32-CAM board to send pictures to Firebase Storage.
Now, go to your Firebase console, and select the
You can check some metadata about the picture and view it in full size.
You can also access the image by accessing the Download URL printed on the Serial Monitor.
Updated 19 September 2023.
To make this project work, the ESP32-CAM needs to be connected to a router with access to the internet – needs to be connected to your local network.
This project is compatible with any ESP32 camera board with the OV2640 camera .
You just need to make sure you use the right pin assignment for the board you’re using: ESP32-CAM Camera Boards: Pin and GPIOs Assignment Guide .
In the Select app field, choose
Now, you should have an app password that you’ll use on the ESP32 code to send the emails.
If you’re using another email provider, check how to create an app password.
You should be able to find the instructions with a quick google search “
After a few seconds, you should have a new email from the ESP32-CAM in your inbox.
As you can see in the image below, the sender’s email name is “ESP32-CAM” as we’ve defined in the code, and the subject “ESP32-CAM Photo Captured”.
Open the email and you should see a photo captured by the ESP32-CAM.
You can open or download the photo to see it in full size.
Alternatively, you can also follow this project by wiring the circuit on a breadboard.
We’re also using a camera module with a longer ribbon .
So that when you mount the shield, the camera is on the same side of the PIR motion sensor.
Alternatively, you can also assemble the circuit on a breadboard.
The shield consists of:
BME280 temperature, humidity and pressure sensor (4 pins);
Mini PIR motion sensor (AM312) ;
Exposed 5V and GND pins to power up the shield and ESP32-CAM;
Other exposed GPIOs if you want to add additional features.
Additionally, you’ll receive a notification with a photo whenever motion is detected.
Finally, only you (or any other authorized user that you want) can control the ESP32-CAM using Telegram.
Having the parts assigned, place each component.
When you’re happy with the layout, make all the connections and route your PCB.
Save your project and export the Gerber files.
Turn your DIY breadboard circuits into professional PCBs – get 10 boards for approximately $5 + shipping (which will vary depending on your country).
Once you have your Gerber files, you can order the PCB.
Follow the next steps to download the file.
1.
Download the Gerber files – click here to download the .zip file
2.
Go to PCBWay website and open the PCB Instant Quote page.
3.
PCBWay can grab all the PCB details and automatically fill them for you.
Use the “Quick-order PCB (Autofill parameters)”.
4.
Press the “+ Add Gerber file” button to upload the provided Gerber files.
And that’s it.
You can also use the OnlineGerberViewer to check if your PCB is looking as it should.
If you aren’t in a hurry, you can use the China Post shipping method to lower your cost significantly.
In our opinion, we think they overestimate the China Post shipping time.
You can increase your PCB order quantity and change the solder mask color.
I’ve ordered the Blue color.
Once you’re ready, you can order the PCBs by clicking “Save to Cart” and complete your order.
Everything comes well packed, and the PCBs are really high-quality.
The letters on the silkscreen are really well-printed and easy to read.
Additionally, the solder sticks easily to the pads.
Besides the PCBs, I also received some gifts (celebration of their 6th anniversary): a badge, some stickers, a t-shirt, a pen and some rulers.
Here’s the soldering tools I’ve used:
TS80 mini portable soldering iron
Solder 60/40 0.5mm diameter
Soldering mat
Read our review about the TS80 Soldering Iron: TS80 Soldering Iron Review – Best Portable Soldering Iron .
The soldering process is pretty simple as you just need to solder the headers pins.
There are some exposed GPIOs in the middle of the shield.
Solder pins to those GPIOs if you want to use them to connect any other peripherals.
Here’s how the ESP32-CAM PCB Shield looks like after assembling.
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
Start a conversation with that bot and type
After a few seconds, the code should be successfully uploaded to your board.
Apply power using the 5V and GND pins on the shield.
Then, press the ESP32-CAM RST button, so that it starts running the code.
Now, open your Telegram account and test your board.
Send the following messages to your ESP32 Telegram bot to control your ESP32-CAM:
If you try to interact with your bot from another account, you’ll get the the “
You also learned how to use your Telegram account to control your ESP32-CAM using a Telegram bot.
This allows you to control and monitor your board from anywhere, as long as you have internet access in your smartphone.
You can also create your own code to do any other tasks with the shield.
We have other similar projects that include building and designing PCBs that you may like:
ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors
Build an All-in-One ESP32 Weather Station Shield
Build a Multisensor Shield for ESP8266
EXTREME POWER SAVING with Microcontroller External Wake Up: Latching Power PCB
Learn more about the ESP32-CAM with our resources:
We have other ESP32-CAM projects in our blog that you might like.
In fact you can take this project further, by adding a PIR sensor to take a photo when motion is detected , a physical pushbutton to take a photo, or also include video streaming capabilities in another URL path.
Other ESP32-CAM projects and tutorials:
ESP32-CAM PIR Motion Detector with Photo Capture (saves to microSD card)
ESP32-CAM Video Streaming and Face Recognition with Arduino IDE
ESP32-CAM Video Streaming Web Server (Home Assistant, Node-RED, etc…)
ESP32-CAM Take Photo and Save to MicroSD Card
ESP32-CAM Troubleshooting Guide
When you access the web server, you’ll see three buttons:
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
In your Arduino IDE Serial Monitor window, you should see similar messages:
We’ll be using the ESP32-CAM board labelled as AI-Thinker module, but other modules should also work by making the correct pin assignment in the code.
The ESP32-CAM board is a $9 device (or less) that combines an ESP32-S chip, an OV2640 camera, a microSD card slot and several GPIO pins.
For an introduction to the ESP32-CAM, you can follow the next tutorials:
ESP32-CAM Video Streaming and Face Recognition with Arduino IDE
ESP32-CAM Video Streaming Web Server (works with Home Assistant, Node-RED, etc…)
ESP32-CAM Troubleshooting Guide
The ESP32-CAM is in deep sleep mode
Press the RESET button to wake up the board
The camera takes a photo
The photo is saved in the microSD card with the name: pictureX.jpg, where X corresponds to the picture number
The picture number will be saved in the ESP32 flash memory so that it is not erased during RESET and we can keep track of the number of photos taken.
Many FTDI programmers have a jumper that allows you to select 3.3V or 5V.
Make sure the jumper is in the right place to select 5V.
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
Check the Arduino IDE Serial Monitor window to see if everything is working as expected.
As you can see, the picture was successfully saved in the microSD card.
To see the photos taken, remove the microSD card from the microSD card slot and insert it into your computer.
You should have all the photos saved.
The quality of your photo depends on your lighting conditions.
Too much light can ruin your photos and dark environments will result in many black pixels.
The ESP32-CAM is a very small camera module with the ESP32-S chip that costs approximately $10.
Besides the OV2640 camera, and several GPIOs to connect peripherals, it also features a microSD card slot that can be useful to store images taken with the camera or to store files to serve to clients.

The following code should load.
Before uploading the code, you need to insert your network credentials in the following variables:
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Then, make sure you select the right camera module.
In this case, we’re using the AI-THINKER Model.
So, comment all the other models and uncomment this one:
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
#define CAMERA_MODEL_AI_THINKER
If none of these correspond to the camera you’re using, you need to add the pin assignment for your specific board in the camera_pins.h tab.
Now, the code is ready to be uploaded to your ESP32.
Many FTDI programmers have a jumper that allows you to select 3.3V or 5V.
Make sure the jumper is in the right place to select 5V.
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
You also have the option to take photos by clicking the
First, you need to enroll a new face.
It will make several attempts to save the face.
After enrolling a new user, it should detect the face later on (subject 0).
And that’s it.
Now you have your video streaming web server up and running with face detection and recognition with the example from the library.
You can integrate this video streaming web server with popular home automation platforms like
If you’re using the same camera module, you don’t need to change anything on the code.
#define CAMERA_MODEL_AI_THINKER
Now, you can upload the code to your ESP32-CAM board.
Many FTDI programmers have a jumper that allows you to select 3.3V or 5V.
Make sure the jumper is in the right place to select 5V.
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
4) When you start to see these dots on the debugging window as shown below, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
Having just the ESP32-CAM working via IP might be useful for most people, but you can integrate this project with Home Assistant (or with other home automation platforms).
Continue reading to learn how to integrate with Home Assistant.
Open
Add a new card to your Dashboard:
Pick a card of the type
In the
If you’re using the configuration file, this is what you need to add.
After that, Home Assistant can display the ESP32-CAM video streaming.
The ESP32-CAM board fits perfectly into the dummy camera enclosure.
You can power it using a 5V power adapter through the ESP32-CAM GND and 5V pins.
Place the surveillance camera in a suitable place.
After that, go to the camera IP address or to your Home Assistant dashboard and see in real time what’s happening.
The following image shows us testing the video streaming camera.
Sara is taking a screenshot while I’m filming the camera.
It’s impressive what this little $9 ESP32 camera module can do and it’s been working reliably.
Now, we can use the surveillance camera to see in real time what’s happening in my front entrance.
For demonstration purposes, we’ll send BME280 sensor readings from one board to the other.
The receiver will display the readings on an OLED display .
If you have an ESP8266 board, you can read this dedicated guide: ESP8266 NodeMCU Client-Server Wi-Fi Communication .
The ESP32 server creates its own wireless network ( ESP32 Soft-Access Point ).
So, other Wi-Fi devices can connect to that network (
For this tutorial, you need the following parts:
2x ESP32 Development boards – read Best ESP32 Boards Review
BME280 sensor
I2C SSD1306 OLED display
Jumper Wires
Breaboard
The ESP32 server is an Access Point (AP) , that listens for requests on the /temperature, /humidity and /pressure URLs.
When it gets requests on those URLs, it sends the latest BME280 sensor readings.
For demonstration purposes, we’re using a BME280 sensor, but you can use any other sensor by modifying a few lines of code.
| VIN/VCC | 3.3V |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
This means that the access point was set successfully.
Now, to make sure it is listening for temperature, humidity and pressure requests, you need to connect to its network.
In your smartphone, go to the Wi-Fi settings and connect to the
While connected to the access point, open your browser and type 192.168.4.1/temperature
You should get the temperature value in your browser:
Try this URL path for the humidity 192.168.4.1/humidity:
Finally, go to 192.168.4.1/pressure URL:
If you’re getting valid readings, it means that everything is working properly.
Now, you need to prepare the other ESP32 board (client) to make those requests for you and display them on the OLED display.
The ESP32 Client is a Wi-Fi station that is connected to the ESP32 Server.
The client requests the temperature, humidity and pressure from the server by making HTTP GET requests on the /temperature, /humidity, and /pressure URL routes.
Then, it displays the readings on an OLED display.
| VIN/VCC | VIN |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
The sensor readings are also displayed in the OLED.
That’s it! Your two boards are talking with each other.
With this setup, you can monitor and control your ESP32 from anywhere in the world, and the ESP32 doesn’t need to be connected to a wireless router because it connects to the internet using a SIM card data plan.
Besides Wi-Fi and Bluetooth, you can communicate with this ESP32 board using SMS or phone calls and you can connect it to the internet using your SIM card data plan.
This is great for IoT projects that don’t have access to a nearby router.
The package includes some header pins, a battery connector, and an external antenna that you should connect to your board.
However, we had some issues with that antenna, so we decided to switch to another type of antenna and all the problems were solved.
The following figure shows the new antenna.
In a previous project , we created our own server with a database to plot sensor readings in charts that you can access from anywhere in the world.
In this project, we’ll publish sensor readings to a server via MQTT and we’ll use Mosquitto broker.
You can publish your sensor readings to any other cloud broker.
In summary, here’s how the project works:
The T-Call ESP32 SIM800L board is connected to the internet using a SIM card data plan.
The T-Call ESP32 SIM800L board publishes the sensor readings via MQTT and the readings are displayed in Node-RED Dashboard.
Through Node-RED Dashboard, you can press buttons to send on and off commands to control the ESP32 GPIOs.
We’ll be using a BME280 sensor , but you can use any other sensor that best suits your needs.
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
After installing the libraries, restart your Arduino IDE.
We’re connecting the BME280’s SDA pin to GPIO 18 and the SCL pin to GPIO 19.
In this example, it publishes new sensor readings every 30 seconds, but for testing purposes you can use a shorter period of time.
Then, open a browser and type your server domain on the
The ESP32 authenticates as a user with email and password (that user must be set on the Firebase authentication methods);
After authentication, the ESP gets the user UID;
The database is protected with security rules.
The user can only access the database nodes under the node with its user UID.
After getting the user UID, the ESP can publish data to the database;
The ESP32 gets temperatrure, humidity and pressure from the BME280 sensor.
It gets epoch time right after gettings the readings (timestamp).
The ESP32 sends temperature, humidity, pressure and timestamp to the database.
New readings are added to the database periodically.
You’ll have a record of all readings on the Firebase realtime database.
These are the main steps to complete this project:
You can continue with the Firebase project
Notice that Firebase creates a unique UID for each registered user.
The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database.
There’s also a column that registers the date of the last sign-in.
At the moment, it is empty because we haven’t signed in with that user yet.
These rules grant access to a node matching the authenticated user’s UID.
This grants that each authenticated user can only access its own data.
This means the user can only access the nodes that are under a node with its corresponding user UID.
If there are other data published on the database, not under a node with the users’ UID, that user can’t access that data.
For example, imagine our user UID is RjO3taAzMMXBB2Xmir2LQ.
With our security rules, it can read and write data to the database under the node UsersData/RjO3taAzMMXBB2Xmir2LQ.
You’ll better understand how this works when you start working with the ESP32.
Not familiar with the BME280 with the ESP32? Read this tutorial:
Then, click
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
Now, you’re all set to start programming the ESP32 board to interact with the database.
It might seem redundant to save the timestamp twice (in the parent node and in the child node), however, having all the data at the same level of the hierarchy will make things simpler in the future, if we want to build a web app to display the data.
The timestamp variable will be used to save time (epoch time format).
int timestamp;
To learn more about getting epoch time with the ESP32 board, you can check the following tutorial:
Get Epoch/Unix Time with the ESP32 (Arduino IDE)
We’ll send all the readings and corresponding timestamp to the realtime database at the same time by creating a JSON object that contains the values of those variables.
The ESP Firebase Client library has its own JSON methods.
We’ll use them to send data in JSON format to the database.
We start by creating a variable of type FirebaseJson called json.
FirebaseJson json;
The ESP_Firebase_Client library provides some examples showing how to use FirebaseJson and how to send data in JSON format to the database: ESP_Firebase_Client library FirebaseJson examples.
We’ll request the time frompool.ntp.org, which is a cluster of time servers that anyone can use to request the time.
const char* ntpServer = "pool.ntp.org";
Then, create an Adafruit_BME280 object called bme.
This automatically creates a sensor object on the ESP32 default I2C pins.
Adafruit_BME280 bme; // I2C
The following variables will hold the temperature, humidity, and pressure readings from the sensor.
float temperature;
float humidity;
float pressure;
Aditionally, go to the Realtime Database on your Firebase project interface and check that new readings are saved.
Notice that it saves the data under a node with the own user UID—this is a way to restrict access to the database.
Wait some time until you get some readings on the database.
Expand the nodes to check the data.
The ESP32 reads temperature using the DS18B20 temperature sensor.
After getting the temperature, it makes a request to an NTP (Network Time Protocol) server to get date and time.
So, the ESP32 needs a Wi-Fi connection.
The data (temperature and timestamp) are logged to a microSD card.
To log data to the microSD card we’re using a microSD card module.
After completing these previous tasks, the ESP32 sleeps for 10 minutes.
The ESP32 wakes up and repeats the process.
ESP32 DOIT DEVKIT V1 Board – read ESP32 Development Boards Review and Comparison
MicroSD card module
MicroSD card
DS18B20 temperature sensor
10k Ohm resistor
Jumper wires
Breadboard
You can also use the following table as a reference to wire the microSD card module:
| 3V3 | 3V3 |
| CS | GPIO 5 |
| MOSI | GPIO 23 |
| CLK | GPIO 18 |
| MISO | GPIO 19 |
| GND | GND |
Press the ESP32 Enable button, and check that everything is working properly (the ESP32 is connected to your local network, and the microSD card is properly attached).
You can copy the file content to a spreadsheet on Google Sheets for example, and then split the data by commas.
To split data by commas, select the column where you have your data, then go to
To successfully follow this tutorial, make sure you follow all the next steps in the following order:
3.
Give a name to your project.
Then, click Create.
Your project will be created successfully.
4.
Now, you need to create a service account for that project.
At the left sidebar, click on
5.
Insert a name for your Service account, then click
6.
Select the service account role.
Select
7.
Finally, click
You successfully create a Service Account.
Now, you need to create a Key.
Then, create a new key.
Then, select
This will download a JSON file to your computer with the key.
Open the file, and you’ll get something similar, but with your own details:
{
"type": "service_account",
"project_id": "...",
"private_key_id": "...",
"private_key": "-----BEGIN PRIVATE KEY----- ...................\n-----END PRIVATE KEY-----\n",
"client_email": ".....",
"client_id": "....",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/...",
"universe_domain": "googleapis.com"
}
Copy the
Save the spreadsheet ID.
It’s highlighted in the picture above.
The Spreadsheet ID is the last string of characters in the URL for your spreadsheet.
For example, in the URL https://docs.google.com/spreadsheets/d/1aISQE8K79LS5c3vF18qFRcmfDRFn_9nE4nKveWBCtoQ/edit#gid=0, the spreadsheet ID is 1aISQE8K79LS5c3vF18qFRcmfDRFn_9nE4nKveWBCtoQ.
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Open the spreadsheet where you’re publishing the values.
You should see new values being published in real-time.
The first column contains the epoch time, then the temperature in Celsius degrees, the humidity, and finally the pressure in hPa.
We’re using the timestamp in epoch time.
To convert it to a readable format, you can simply use the EPOCHTODATE() function .
Before proceeding with this tutorial you need to have the ESP32 add-on installed in your Arduino IDE:
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)
| %A | Full weekday name |
| %B | Full month name |
| %d | Day of the month |
| %Y | Year |
| %H | Hour in 24h format |
| %I | Hour in 12h format |
| %M | Minute |
| %S | Second |
ESP32 DOIT DEVKIT V1 Board – read ESP32 Development Boards Review and Comparison
Mini DC motor
L298N motor driver
Power source:4x 1.5 AA batteriesor Bench power supply
100nF ceramic capacitor (optional)
1x SPDT slide switch (optional)
Jumper wires
The motor driver has a two-terminal block on each side for each motor.
| SIGNAL ON THE ENABLE PIN | MOTOR STATE |
|---|---|
| HIGH | Motor enabled |
| LOW | Motor not enabled |
| PWM | Motor enabled: speed proportional to the duty cycle |
| 0 | 1 | 1 | |
| 1 | 0 | 1 | |
| 0 | 0 | 0 |
| DIRECTION | INPUT 1 | INPUT 2 | INPUT 3 | INPUT 4 |
|---|---|---|---|---|
| Forward | 0 | 1 | 0 | 1 |
| Backward | 1 | 0 | 1 | 0 |
| Right | 0 | 1 | 0 | 0 |
| Left | 0 | 0 | 0 | 1 |
| Stop | 0 | 0 | 0 | 0 |
| GPIO 27 | GPIO 26 | GPIO 14 | GND |

The ESP32 Espressif datasheet also provides a table comparing the power consumption of the different power modes.
And here’s also
If you put your ESP32 in deep sleep mode, it will reduce the power consumption and your batteries will last longer.
Having your ESP32 in deep sleep mode means cutting with the activities that consume more power while operating, but leave just enough activity to wake up the processor when something interesting happens.
In deep sleep mode neither CPU or Wi-Fi activities take place, but the Ultra Low Power (ULP) co-processor can still be powered on.
While the ESP32 is in deep sleep mode the RTC memory also remains powered on, so we can write a program for the ULP co-processor and store it in the RTC memory to access peripheral devices, internal timers, and internal sensors.
This mode of operation is useful if you need to wake up the main CPU by an external event, timer, or both, while maintaining minimal power consumption.
The ESP32 RTC controller has a built-in timer you can use to wake up the ESP32 after a predefined amount of time.
Every 5 seconds, the ESP wakes up, prints a message on the serial monitor, and goes to deep sleep again.
Every time the ESP wakes up the bootCount variable increases.
It also prints the wake up reason as shown in the figure below.
However, notice that if you press the EN button on the ESP32 board, it resets the boot count to 1 again.
You can modify the provided example, and instead of printing a message you can make your ESP do any other task.
The timer wake up is useful to perform periodic tasks with the ESP32, like daily tasks, without draining much power.
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
Press the pushbutton to wake up the ESP32.
Try this several times, and see the boot count increasing in each button press.
Using this method is useful to wake up your ESP32 using a pushbutton, for example, to make a certain task.
However, with this method you can only use one GPIO as wake up source.
What if you want to have different buttons, all of them wake up the ESP, but do different tasks? For that you need to use the ext1 method.
3.
Copy the Hex number to the BUTTON_PIN_BITMASK variable, and you should get:
#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex
Open the Serial Monitor at a baud rate of 115200.
Press the pushbuttons to wake up the ESP32.
You should get something similar on the serial monitor.

To interact with Deta base using the ESP32, we’ll use the detaBaseArduinoESP32 library .
The present tutorial was based on the guides created by the library developer.
You can find the guides on the following link:
ESP32 Deta Base Guides by Kushagra Goel
Deta Base is a fully-managed, fast, scalable and secure NoSQL database with a focus on end-user simplicity. It offers a UI through which you can easily see, query, update and delete records in the database. https://docs.deta.sh/docs/base/aboutAnd the best part is that Deta Base is
Your data is encrypted and stored safely on AWS. Encryption keys are managed by AWS; AWS manages Exabytes of the world’s most sensitive data. https://docs.deta.sh/docs/base/about#is-my-data-secureWe recommend taking a look at the docs to get more familiar with Deta Base: Deta Base documentation Deta Base is still in the beta version, so you may expect improvements in the future.
Enter a username, password, and email to create a new account.
Deta base will send you a verification email.
Verify your account, and you should be redirected to your Deta dashboard.
The following window pops up:
By default, it creates a new project called “default”.
As mentioned, projects are accessed via ids and keys.
When you click on the
When you’re done.
Click
And your database should look as follows.
The web server we’ll build updates the readings automatically without the need to refresh the web page.
With this project you’ll learn:
How to read temperature and humidity from DHT sensors;
Build an asynchronous web server using the ESPAsyncWebServer library ;
Update the sensor readings automatically without the need to refresh the web page.
For a more in-depth explanation on how to use the DHT22 and DHT11 temperature and humidity sensors with the ESP32, read our complete guide: ESP32 with DHT11/DHT22 Temperature and Humidity Sensor using Arduino IDE
To complete this tutorial you need the following parts:
ESP32 development board (readESP32 development boards comparison )
DHT22 orDHT11 Temperature and Humidity Sensor
4.7k Ohm Resistor
Breadboard
Jumper wires
(This schematic uses the ESP32 DEVKIT V1 module version with 36 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
As you can see in the above figure, the web page shows one heading and two paragraphs.
There is a paragraph to display the temperature and another to display the humidity.
There are also two icons to style our page.
Let’s see how this web page is created.
All the HTML text with styles included is stored in the index_html variable.
Now we’ll go through the HTML text and see what each part does.
The following <meta> tag makes your web page responsive in any browser.
<meta name="viewport" content="width=device-width, initial-scale=1">
The <link> tag is needed to load the icons from the fontawesome website.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
Search the icon you’re looking for.
For example, “thermometer”.
Click the desired icon.
Then, you just need to copy the HTML text provided.
<i>
To chose the color, you just need to pass the style parameter with the color in hexadecimal, as follows:
<i></i>
Proceeding with the HTML text…
The next line writes the word “Temperature” into the web page.
<span>Temperature</span>
The TEMPERATURE text between % signs is a placeholder for the temperature value.
<span>%TEMPERATURE%</span>
This means that this


If you see a lot of dots (…__…__) on the debugging window and the “Failed to connect to ESP32: Timed out waiting for packet header” message, that means you need to press the ESP32 on-board BOOT button after the dots start appearing.
And turn off when you release it:
The electrical circuit is closed when a magnet is near the switch—door closed.
When the magnet is far away from the switch—door open—the circuit is open.
See the figure below.
Your Applet was successfully created.
Now, let’s test it.
Now, let’s trigger the event to test it.
In the {event} placeholder, write the event you created previously.
In our case, it is
You should get a success message saying “Event has been triggered” and you should get an email in your inbox informing you that the event has been triggered.
If you received the email, your Applet is working as expected.
You can proceed to the next section.
We’ll program the ESP32 to trigger your Applet when the door changes state.
For prototyping/testing you can applythe magnetic reed switch to your door using Velcro.
Now when someoneopens/closes your door you get notified via email.
The electrical circuit is closed when a magnet is near the switch—door closed.
When the magnet is far away from the switch—door open—the circuit is open.
See the figure below.
“Bots are third-party applications that run inside Telegram.
Users can interact with bots by sending them messages, commands, andinline requests.
You control your bots using HTTPS requests to Telegram Bot API“.
The ESP32 will interact with the Telegram bot to send messages to your Telegram account.
Whenever the door changes state, you’ll receive a notification on your smartphone (as long as you have access to the internet).
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open, and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
And that’s it! You can proceed to the next section.
Start a conversation with that bot and type
For prototyping/testing, you can applythe magnetic reed switch to your door using Velcro.
Now when someoneopens/closes your door, you receive a message in your Telegram account.
Each DS18B20 temperature sensor has a unique 64-bit serial code.
This allows you to wire multiple sensors to the same data wire.
So, you can get temperature from multiple sensors using just one GPIO.
The DS18B20 temperature sensor is also available in waterproof version .
Here’s a summary of the most relevant specs of the DS18B20 temperature sensor:
Communicates over one-wire bus communication
Power supply range: 3.0V to 5.5V
Operating temperature range: -55oC to +125oC
Accuracy +/-0.5 oC (between the range -10oC to 85oC)
For more information consult the DS18B20 datasheet .
3.
Then, search for “
After installing the libraries, restart your Arduino IDE.
The DS18B20 temperature sensor communicates using one-wire protocol and each sensor has a unique 64-bit serial code, so you can read the temperature from multiple sensors using just one single GPIO.
You just need to wire all data lines together as shown in the following schematic diagram:
We have a dedicated article on how to interface multiple DS18B20 temperature sensors with the EPS32.
Just follow the next tutorial:
ESP32 with Multiple DS18B20 Temperature Sensors
To build the web server we’ll use theESPAsyncWebServer library that provides an easy way to build an asynchronous web server.
Building an asynchronous web server has several advantages.
We recommend taking a quick look at the library documentation on its GitHub page .
When we upload code to the ESP32 using the Arduino IDE, it just runs – we don’t have to worry which core executes the code.
There’s a function that you can use to identify in which core the code is running:
xPortGetCoreID()
If you use that function in an Arduino sketch, you’ll see that both the setup() and loop() are running on core 1.
Test it yourself by uploading the following sketch to your ESP32.
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
void setup() {
Serial.begin(115200);
Serial.print("setup() running on core ");
Serial.println(xPortGetCoreID());
}
void loop() {
Serial.print("loop() running on core ");
Serial.println(xPortGetCoreID());
}
View raw code
Open the Serial Monitor at a baud rate of 115200 and check the core the Arduino sketch is running on.
We’ll create two tasks running on different cores:
Task1 runs on core 0;
Task2 runs on core 1;
Upload the next sketch to your ESP32 to blink each LED in a different core:
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
TaskHandle_t Task1;
TaskHandle_t Task2;
// LED pins
const int led1 = 2;
const int led2 = 4;
void setup() {
Serial.begin(115200);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function.
*/
"Task1", /* name of task.
*/
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function.
*/
"Task2", /* name of task.
*/
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
}
//Task1code: blinks an LED every 1000 ms
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000);
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * pvParameters ){
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led2, HIGH);
delay(700);
digitalWrite(led2, LOW);
delay(700);
}
}
void loop() {
}
View raw code
As expected Task1 is running on core 0, while Task2 is running on core 1.
In your circuit, one LED should be blinking every 1 second, and the other should be blinking every 700 milliseconds.
We’ll read the temperature using a DS18B20 sensor and send emails using an SMTP Server .
The ESP32 will be programmed using Arduino IDE .
To better understand how this project works, we recommend taking a look at the following tutorials:
ESP32 Send Emails using an SMTP Server: HTML, Text and Attachments (Arduino IDE)
Input Data on HTML Form ESP32/ESP8266 Web Server (Arduino IDE)
ESP32/ESP8266 Thermostat Web Server – Control Output Based on Temperature
The ESP32 hosts a web server that shows the latest temperature readings from a DS18B20 temperature sensor.
There’s an input field to set up a threshold.
When the temperature goes above or below the threshold value, you’ll receive an email.
You can also set up the recipient’s email address on the web page.
The system can be activated or deactivated through the web server.
If you choose to deactivate the system, you won’t receive email notifications when the temperature crosses the threshold value.
The following image shows an overview of the web server page.
In the Select app field, choose
Now, you should have an app password that you’ll use on the ESP32 code to send the emails.
If you’re using another email provider, check how to create an app password.
You should be able to find the instructions with a quick google search “
To follow this tutorial you need the following parts:
ESP32 (read Best ESP32 development boards )
DS18B20 temperature sensor (waterproof version ) – complete Guide
4.7k Ohm resistor
Jumper wires
Breadboard
Open the Serial Monitor at a baud rate of 115200 and press the on-board RST button.
The ESP32 will print its IP address and it will start displaying new temperature values every 5 seconds.
Open a browser and type the ESP32 IP address.
A similar web page should load with the default values (defined in your code):
If the email notifications are enabled (checkbox checked) and if the temperature goes above the threshold, you’ll receive an email notification.
After that, when the temperature goes below the threshold, you’ll receive another email.
You can use the web page input fields to set up a different recipient’s email address, to enable or disable email notifications, and to change the threshold value.
For any change to take effect, you just need to press the “Submit” button.
At the same time, you should get the new input fields in the Serial Monitor.
If you’re new to ESP-NOW, we recommend reading the following getting started guide first to get familiar with ESP-NOW concepts and functions on the ESP32:
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
Save your board MAC address because you’ll need it in the next ESP-NOW examples.
Here are the main steps:
The sender sets its PMK;
The sender adds the receiver as a peer and sets its LMK;
The receiver sets its PMK (should be the same of the receiver);
The receiver adds the sender as a peer and sets its LMK (should be the same as the one set on the sender board);
The sender sends the following structure to the receiver board:
typedef struct struct_message {
int counter;
int x;
int y;
} struct_message;
The receiver gets the message.
On the sender board, you should get “Delivery Success” messages.
We have other guides related to ESP-NOW that you might be interested in:
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
ESP-NOW Two-Way Communication Between ESP32 Boards
ESP-NOW with ESP32: Send Data to Multiple Boards (one-to-many)
ESP-NOW with ESP32: Receive Data from Multiple Boards (many-to-one)
There are a few things you need to take into account if you want to use Wi-Fi to host a web server and use ESP-NOW simultaneously to receive sensor readings from other boards:
The ESP32 sender boards must use the same Wi-Fi channel of the receiver board.
The Wi-Fi channel of the receiver board is automatically assigned by your Wi-Fi router.
The Wi-Fi mode of the receiver board must be access point and station (WIFI_AP_STA).
You can set up the same Wi-Fi channel manually, or you can add a simple spinet of code on the sender to set its Wi-Fi channel to the same of the receiver board.
There are two ESP32 sender boards that send DHT22 temperature and humidity readings via ESP-NOW to one ESP32 receiver board ( ESP-NOW many to one configuration );
The ESP32 receiver board receives the packets and displays the readings on a web server;
The web server is updated automatically every time it receives a new reading using Server-Sent Events (SSE).
3.
After installing the DHT library from Adafruit, type “
After installing the libraries, restart your Arduino IDE.
To learn more about the DHT11 or DHT22 temperature sensor, read our guide: ESP32 with DHT11/DHT22 Temperature and Humidity Sensor using Arduino IDE .
After uploading the code to the receiver board, press the on-board EN/RST button.
The ESP32 IP address should be printed on the Serial Monitor as well as the Wi-Fi channel.
Upload the following code to each of your sender boards.
Don’t forget to increment theidnumber for each sender board and insert your SSID in the WIFI_SSID variable.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-esp-now-wi-fi-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1
// Digital pin connected to the DHT sensor
#define DHTPIN 4
// Uncomment the type of sensor in use:
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
//MAC Address of the receiver
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
int id;
float temp;
float hum;
int readingId;
} struct_message;
//Create a struct_message called myData
struct_message myData;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
unsigned int readingId = 0;
// Insert your SSID
constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";
int32_t getWiFiChannel(const char *ssid) {
if (int32_t n = WiFi.scanNetworks()) {
for (uint8_t i=0; i<n; i++) {
if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
return WiFi.channel(i);
}
}
}
return 0;
}
float readDHTTemperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return 0;
}
else {
Serial.println(t);
return t;
}
}
float readDHTHumidity() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return 0;
}
else {
Serial.println(h);
return h;
}
}
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup() {
//Init Serial Monitor
Serial.begin(115200);
dht.begin();
// Set device as a Wi-Fi Station and set channel
WiFi.mode(WIFI_STA);
int32_t channel = getWiFiChannel(WIFI_SSID);
WiFi.printDiag(Serial); // Uncomment to verify channel number before
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
WiFi.printDiag(Serial); // Uncomment to verify channel change after
//Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
esp_now_register_send_cb(OnDataSent);
//Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.encrypt = false;
//Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
//Set values to send
myData.id = BOARD_ID;
myData.temp = readDHTTemperature();
myData.hum = readDHTHumidity();
myData.readingId = readingId++;
//Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
Serial.println("Sent with success");
}
else {
Serial.println("Error sending the data");
}
}
}
View raw code
Open a browser on your local network and type the ESP32 IP address.
It should load the temperature, humidity, and reading IDs for each board.
Upon receiving a new packet, your web page updates automatically without refreshing the web page.
Getting analog readings with ESP32 and ESP8266 is a bit different, so there is a section for each board in this tutorial.
The following table shows some differences between analog reading on the ESP8266 and the ESP32.
| A0 (ADC 0) | GPIOs: 0, 2, 4, 12, 13, 14, 15, 25, 26, 27, 32, 33, 34, 35, 36, and 39. | |
| 10-bit (0-1023) | 12-bit (0-4095) | |
| No | Yes |
In this example we’re using GPIO 34 to read analog values from the potentiometer, but you can choose any other GPIO that supports ADC.
Read our ESP32 Pinout Guide to learn more about the ESP32 GPIOs.
The ESP8266 supports analog reading only on the A0 pin.
Check the shell of your MicroPython IDE to read the values from the potentiometer.
If you’re using an ESP32 you should get readings between 0 and 4095 — or readings between 0 and 1023 with an ESP8266.
The idea of using the OLED display with the ESP32 or ESP8266 is to ilustrate how you can create a physical user interface for your boards.
The temperature and humidity will be measured using the DHT22 temperature and humidity sensor (you can also use DHT11 ).
If you’re not familiar with the DHT11/DHT22 sensor, we recommend reading the following guide:
ESP32 with DHT11/DHT22 Sensor (Arduino IDE)
In this case we’re connecting the DHT data pin to GPIO 14, but you can use any other suitable GPIO.
On the ESP8266, the pin marked as D1 corresponds to GPIO 5 and the pin marked as D2 corresponds to GPIO 4.
Other Firebase Tutorials with the ESP32 that you might be interested in:
ESP32: Getting Started with Firebase (Realtime Database)
ESP32 with Firebase – Creating a Web App
Notice that Firebase creates a unique UID for each registered user.
The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database.
There’s also a column that registers the date of the last sign-in.
At the moment, it is empty because we haven’t signed in with that user yet.
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
Now, you’re all set to start programming the ESP32 or ESP8266 board to interact with the database.
Then, go to your Firebase project console to check if it signed in as a user.
Go to
Congratulations! You successfully signed in your ESP32/ESP8266 board as a user.
You can combine this example with one of our previous tutorials to send sensor readings to the database as an authorized user: ESP32: Getting Started with Firebase (Realtime Database)
Here’s Part 2 of this project: ESP32/ESP8266: Firebase Web App to Display Sensor Readings (with Authentication)
Other Firebase Tutorials with the ESP32/ESP8266 that you might be interested in:
ESP32: Getting Started with Firebase (Realtime Database)
ESP8266 NodeMCU: Getting Started with Firebase (Realtime Database)
ESP32 with Firebase – Creating a Web App
ESP8266 NodeMCU with Firebase – Creating a Web App
ESP32/ESP8266 Firebase Authentication (Email and Password)
The ESP32/ESP8266 authenticates as a user with email and password (that user must be set on the Firebase authentication methods);
After authentication, the ESP gets the user UID;
The database is protected with security rules.
The user can only access the database nodes under the node with its user UID.
After getting the user UID, the ESP can publish data to the database;
The ESP sends temperature, humidity and pressure to the database.
These are the main steps to complete this project:
You can continue with the Firebase project
Notice that Firebase creates a unique UID for each registered user.
The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database.
There’s also a column that registers the date of the last sign-in.
At the moment, it is empty because we haven’t signed in with that user yet.
These rules grant access to a node matching the authenticated user’s UID.
This grants that each authenticated user can only access its own data.
This means the user can only access the nodes that are under a node with its corresponding user UID.
If there are other data published on the database, not under a node with the users’ UID, that user can’t access that data.
For example, imagine our user UID is RjO3taAzMMXBB2Xmir2LQ.
With our security rules, it can read and write data to the database under the node UsersData/RjO3taAzMMXBB2Xmir2LQ.
You’ll better understand how this works when you start working with the ESP32/ESP8266.
Not familiar with the BME280 with the ESP32? Read this tutorial:
Not familiar with the BME280 with the ESP8266? Read this tutorial:
Then, click
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
Now, you’re all set to start programming the ESP32 and ESP8266 boards to interact with the database.
Aditionally, go to the Realtime Database on your Firebase project interface and check that new readings are saved.
Notice that it saves the data under a node with the own user UID—this is a way to restrict access to the database.
And that’s it.
You’ve successfully sent sensor readings to the Firebase Realtime Database, and you protected the data using database rules.
This project is Part 2 of the following tutorial (there is a version for ESP32 and a version for ESP8266):
ESP32 Data Logging to Firebase Realtime Database
ESP8266 Data Logging to Firebase Realtime Database
You must follow one of those tutorials first, before proceeding
Here’s a summary of the web app features:
login with email and password
displays time of the last update
cards to display the last sensor readings
gauges to display the last sensor readings
charts that display data history with timestamps
select how many readings to display on charts
checkboxes to enable/disable the different display options
table that displays all readings saved on the database
button to delete database data
After this, you can also access thefirebaseConfigobject if you go to your Project settings in your Firebase console.
The index.html file contains some HTML text to build a web page.
For now, leave the default HTML text.
The idea is to replace that with your own HTML text to build a custom web page for your needs.
We’ll do that later in this tutorial.
You should get a
The web page you’ve seen previously is built with the HTML file placed in the public folder of your Firebase project.
By changing the content of that file, you can create your own web app.
That’s what we’re going to do in the next section.
Then, copy the following to the style.css file
html {
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: inline-block;
text-align: center;
}
body {
margin: 0;
width: 100%;
}
.topnav {
overflow: hidden;
background-color: #049faa;
color: white;
font-size: 1rem;
padding: 5px;
}
#authentication-bar{
background-color:mintcream;
padding-top: 10px;
padding-bottom: 10px;
}
#user-details{
color: cadetblue;
}
.content {
padding: 20px;
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
padding: 5%;
}
.cards {
max-width: 800px;
margin: 0 auto;
margin-bottom: 10px;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 2fr));
}
.reading {
color: #193036;
}
.date-time{
font-size: 0.8rem;
color: #1282A2;
}
button {
background-color: #049faa;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
border-radius: 4px;
}
button:hover {
opacity: 0.8;
}
.deletebtn{
background-color: #c52c2c;
}
.form-elements-container{
padding: 16px;
width: 250px;
margin: 0 auto;
}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
table {
width: 100%;
text-align: center;
font-size: 0.8rem;
}
tr, td {
padding: 0.25rem;
}
tr:nth-child(even) {
background-color: #f2f2f2
}
tr:hover {
background-color: #ddd;
}
th {
position: sticky;
top: 0;
background-color: #50b8b4;
color: white;
}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: #474e5d;
padding-top: 50px;
}
/* Modal Content/Box */
.modal-content {
background-color: #fefefe;
margin: 5% auto 15% auto; /* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 80%; /* Could be more or less, depending on screen size */
}
/* Style the horizontal ruler */
hr {
border: 1px solid #f1f1f1;
margin-bottom: 25px;
}
/* The Modal Close Button (x) */
.close {
position: absolute;
right: 35px;
top: 15px;
font-size: 40px;
font-weight: bold;
color: #f1f1f1;
}
.close:hover,
.close:focus {
color: #f44336;
cursor: pointer;
}
/* Clear floats */
.clearfix::after {
content: "";
clear: both;
display: table;
}
/* Change styles for cancel button and delete button on extra small screens */
@media screen and (max-width: 300px) {
.cancelbtn, .deletebtn {
width: 100%;
}
}
View raw code
The CSS file includes some simple styles to make our webpage look better.
We won’t discuss how CSS works in this tutorial.
Firebase offers a free hosting service to serve your assets and web apps.
Then, you can access your web app from anywhere.
You can use the Hosting URL provided to access your web app from anywhere.
Insert the email and password of the authorized user you added in the Firebase Authentication methods.
If the form doesn’t show up at first, refresh the web page.
After that, you can access the web page with the readings.
The readings are displayed in cards, gauges, charts, and a table.
You can also select which interfaces you want to see by checking/unchecking the checkboxes.
You can also check the readings displayed on charts.
You can select the charts range, but keep in mind that selecting more than 30 readings will take some time.
Finally, if you want to see all the readings.
You can open the readings table.
At the end of the table, there’s a button to load more readings until all readings are displayed.
There is also a button to delete all data if you want to remove all readings from the database.
Here’s a video showing how the web app works.
This article is Part 2 of this previous tutorial: ESP32/ESP8266 Firebase: Send BME280 Sensor Readings to the Realtime Database .
Follow that tutorial first, before proceeding.
Firebase hosts your web app over a global CDN using Firebase Hosting and provides an SSL certificate.
You can access your web app from anywhere using the Firebase-generated domain name.
When you first access the web app, you need to authenticate with an authorized email address and password.
You already set up that user and the authentication method in Part 1 .
After authentication, you can access a web app page that shows the sensor readings saved on the realtime database.
The realtime database was set up on Part 1 .
Once you’re logged in, you can logout any time.
The next time you’ll acces the app you’ll need to login again.
After this, you can also access thefirebaseConfigobject if you go to your Project settings in your Firebase console.
The index.html file contains some HTML text to build a web page.
For now, leave the default HTML text.
The idea is to replace that with your own HTML text to build a custom web page for your needs.
We’ll do that later in this tutorial.
You should get a
The web page you’ve seen previously is built with the HTML file placed in the public folder of your Firebase project.
By changing the content of that file, you can create your own web app.
That’s what we’re going to do in the next section.
Then, copy the following to the style.css file
html {
font-family: Verdana, Geneva, Tahoma, sans-serif;
display: inline-block;
text-align: center;
}
p {
font-size: 1.2rem;
}
body {
margin: 0;
}
.topnav {
overflow: hidden;
background-color: #049faa;
color: white;
font-size: 1rem;
padding: 10px;
}
#authentication-bar{
background-color:mintcream;
padding-top: 10px;
padding-bottom: 10px;
}
#user-details{
color: cadetblue;
}
.content {
padding: 20px;
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
padding: 5%;
}
.cards {
max-width: 800px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.reading {
font-size: 1.4rem;
}
button {
background-color: #049faa;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
border-radius: 4px;
}
button:hover {
opacity: 0.8;
}
.form-elements-container{
padding: 16px;
width: 250px;
margin: 0 auto;
}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
View raw code
The CSS file includes some simple styles to make our webpage look better.
We won’t discuss how CSS works in this tutorial.
Firebase offers a free hosting service to serve your assets and web apps.
Then, you can access your web app from anywhere.
You can use the Hosting URL provided to access your web app from anywhere.
The web app is responsive, and you can access it using your smartphone, computer, or tablet.
Insert the email and password of the authorized user you added in the Firebase Authentication methods.
After that, you can access the latest sensor readings.
Go to your project’s Firebase console
Throughout this article, we’ll cover the following subjects:
To simplify, HTTPS is just the HTTP protocol but with encrypted data using SSL/TLS.
The disadvantage of using a symmetric key algorithm is that keys are hard to share and you need to be careful how and with who you distribute the key.
How does asymmetric key encryption work? Very briefly:
You have two asymmetric keys: a public key and a private key.
The public key and private key work together.
The public key, as the name suggests, is visible to anyone.
Only the private key can decrypt the message encrypted with the corresponding public key.
You, the client on your browser, try to connect with the server (
Your browser then checks if the certificate is valid (if it was signed with a root certificate on the database of trusted root certificates) and displays a green lock icon on the browser bar if it is.
The web browser will display a warning sign and the HTTPS letters in red.
This means the website has a certificate, but the certificate is unverified (like self-signed certificates) or out of date.
This means that the connection between you and the server is encrypted, but no one can guarantee that the domain really belongs to the company indicated on the site.
Self-signed certificates are fine to use on your DIY and IoT projects, intranets, like your local network, or inside a company’s network.
However, if you’re creating a project for a company that will be accessed by clients outside the company network, like a public website, it’s best to use a certificate from a Certificate Authority.
SSL certificates have an expiry date.
So, if you’re using an ESP32 to connect to a website via HTTPS, you should keep in mind that you’ll need to update the code with the new website’s certificate in the future.
If you’re still confused about all of these new terms, we recommend taking a look at the following website that explains in a fun way how everything works: https://howhttps.works/.
If you’re using the WiFiClient library, you just need to make the following changes:
Use WiFiClientSecure.h library instead of WiFiClient.h
Use port 443 instead of port 80
Change the host URL to https instead of http
With this, you ensure that your communication is encrypted using TLS.
An additional security step is to check the server certificate (the certificate of the website you want to connect to).
You can skip this step while testing and prototyping.
The communication will be encrypted, but you won’t be sure of the integrity of the server you are trying to communicate with.
You can also find examples using HTTPS with the HTTPClient library.
If you want to start working on your HTTPS requests right away, take a look at the examples provided in the ESP32 package for the Arduino core.
WiFiClientSecure example:
At the moment, there are not many examples of building an HTTPS web server with the ESP32 using the Arduino core.
Unfortunately, the AsyncWebServer library that we use in most of our projects, doesn’t fully support HTTPS at the moment.
Nevertheless, there is another library that provides easy methods to build an ESP32 HTTPS web server, including an example that generates certificates on the fly.
Here’s a link to the library: esp32_https_server library .
If you’re familiar with ESP-IDF, you can take a look at the documentation on the following link:
ESP-IDF HTTPS Server Documentation
There are several examples that show how to make HTTPS requests with the ESP8266.
You can check the examples available in your Arduino IDE.
Make sure you have the latest version of the ESP8266 boards installed to make sure you have access to the latest version of the examples and that these will work.
To update the ESP8266 boards’ installation, you just need to go to
The ESP8266 is not optimized for SSL cryptography, so running an HTTPS Server on the ESP8266 is very demanding.
You need to set the clock frequency to 160MHz and even so, you might get unexpected resets on the board.
For an ESP8266 HTTPS web server, you can take a look at an example using the ESP8266WebServer library on the following link:
ESP8266 HTTPS Server (BearSSL)
Wire your LCD to the ESP32 by following the next schematic diagram.We’re using the ESP32 default I2C pins (GPIO 21 and GPIO 22).
You can also use the following table as a reference.
| GND | GND |
| VCC | VIN |
| SDA | GPIO 21 |
| SCL | GPIO 22 |
You can also use the following table as a reference.
| GND | GND |
| VCC | VIN |
| SDA | GPIO 4 (D2) |
| SCL | GPIO 5 (D1) |
In this case the address is
In this simple sketch we show you the most useful and important functions from the LiquidCrystal_I2C library.
So, let’s take a quick look at how the code works.
Copy the byte variable to your code (before the setup()).
You can call it heart:
byte heart[8] = {
0b00000,
0b01010,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00000
};
Then, in the setup(), create a custom character using the createChar() function.
This function accepts as arguments a location to allocate the char and the char variable as follows:
lcd.createChar(0, heart);
Then, in the loop(), set the cursor to where you want the character to be displayed:
lcd.setCursor(0, 0);
Use the write() method to display the character.
Pass the location where the character is allocated, as follows:
lcd.write(0);
You have a web page with three input fields that you can access with any browser in your network.
When you type a new value and press the “Submit” button, your ESP will update a variable with the new value.
If you ever needed to update a variable through an ESP web server, you should follow this project.
With this method, you avoid hard coding variables because you can create an input field in a web page to update any variable with a new value.
This can be specially useful to set threshold values, set SSID/password, change API Keys, etc…
Later, we’ll also show you how to save those variables permanently using SPIFFS and how to access them.
Here’s how this second example works.
This web page allows you to enter three types of variables: String, Int and Float.
Then, every time you submit a new value, that value is stored in a SPIFFS file.
This web page also contains a placeholder to show the current values.
To learn more about building a web server using SPIFFS, you can refer to the next tutorials:
ESP32 Web Server using SPIFFS (SPI Flash File System)
ESP8266 NodeMCU Web Server using SPIFFS (SPI Flash File System)
Let’s take a look at the first form to see how it works (the other forms work in a similar way).
<form action="/get">
input1: <input type="text" name="input1">
<input type="submit" value="Submit">
</form>
The action attribute specifies where to send the data inserted on the form after pressing submit.
In this case, it makes an HTTP GET request to /get?input1=value.
The value refers to the text you enter in the input field.
Then, we define two input fields: one text field and one submit button.
The following line defines a one line text input field.
input1: <input type="text" name="input1">
The type attribute specifies we want a text input field, and the name attribute specifies the name of the input element.
The next line defines a button for submitting the HTML form data.
<input type="submit" value="Submit">
In this case, the type attribute specifies you want a submit button, and the value specifies the text on the button.
If you make a request on an invalid URL, we call the notFound() function, defined at the beginning of the sketch.
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
Finally, start the server to handle clients.
server.begin();
Then, open your browser and type the IP address.
This web page should load:
For example, type
Open your browser and type the IP address.
A similar web page should load (at first your current values will be blank).
Type a String in the first input field and press “Submit”, repeat the same process for the Int and Float input values.
Every time you press the Submit button for a field, you’ll see an alert message like this:
Press the “OK” button to reload the web page and see the current values updated.
If you have your Arduino IDE Serial Monitor open, you’ll see that the stored values are being printed over and over again:
For a final project, you can delete all those lines in your loop() that print all stored values every 5 seconds, we just left them on purpose for debugging.
A new window opens, name your filemain.pyand save it in your computer:
After that, you should see the following in your uPyCraft IDE (theboot.pyfile in your device and a new tab with themain.pyfile):
Click the
The device directory should now load themain.pyfile.
Your ESP has the filemain.pystored.
Create a socket using socket.socket(), and specify the socket type.
We create a new socket object called s with the given address family, and socket type.
This is a STREAM TCP socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Next, bind the socket to an address (network interface and port number) using the bind() method.
The bind() method accepts a tupple variable with the ip address, and port number:
s.bind(('', 80))
In our example, we are passing an empty string ‘ ‘ as an IP address and port 80.
In this case, the empty string refers to the localhost IP address (this means the ESP32 or ESP8266 IP address).
The next line enables the server to accept connections; it makes a “listening” socket.
The argument specifies the maximum number of queued connections.
The maximum is 5.
s.listen(5)
In the while loop is where we listen for requests and send responses.
When a client connects, the server calls the accept() method to accept the connection.
When a client connects, it saves a new socket object to accept and send data on the conn variable, and saves the client address to connect to the server on the addr variable.
conn, addr = s.accept()
Then, print the address of the client saved on the addr variable.
print('Got a connection from %s' % str(addr))
The data is exchanged between the client and server using the send() and recv() methods.
The following line gets the request received on the newly created socket and saves it in the request variable.
request = conn.recv(1024)
The recv() method receives the data from the client socket (remember that we’ve created a new socket object on the conn variable).
The argument of the recv() method specifies the maximum data that can be received at once.
The next line simply prints the content of the request:
print('Content = %s' % str(request))
Then, create a variable called response that contains the HTML text returned by the web_page() function:
response = web_page()
Finally, send the response to the socket client using the send()and sendall() methods:
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
In the end, close the created socket.
conn.close()
After a few seconds, it should establish a connection with your router and print the IP address on the Shell.
Open your browser, and type your ESP IP address you’ve just found.
You should see the web server page as shown below.
When you press the ON button, you make a request on the ESP IP address followed by /?led=on.
The ESP32/ESP8266 on-board LED turns on, and the GPIO state is updated on the page.
When you press the OFF button, you make a request on the ESP IP address followed by /?led=off.
The LED turns off, and the GPIO state is updated.
To follow this tutorial you need the following parts:
ESP32 or ESP8266 (read ESP32 vs ESP8266 )
BME280 sensor
Breadboard
Jumper wires
| SCK (SCL Pin) | GPIO 22 |
| SDI (SDA pin) | GPIO 21 |
| SCK (SCL Pin) | GPIO 5 |
| SDI (SDA pin) | GPIO 4 |
Then, upload the code to your board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve inserted your networks credentials in the code.
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the board “
You can select each point to see the exact timestamp.
First, the ESP connects to your Wi-Fi network;
Then, the BME280 takes the temperature, humidity, and pressure readings;
Your ESP32 or ESP8266 communicates with the IFTTT Webhooks service that publishes thereadings to a spreadsheet on Google Sheets that is saved in your Google Drive’s folder;
After publishing the readings, the ESP goes into deep sleep mode for 30 minutes;
After 30 minutes the ESP wakes up;
After waking up, the ESP connects to Wi-Fi, and the process repeats.
Continue reading this post to see how to integrate the IFTTT Google Sheets service with your ESP32 or ESP8266.
(This schematic uses the ESP32 DEVKIT V1 module version with 36 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)

After installing the libraries, restart your Arduino IDE.
The ESP32 chip has a built-in clock, so the readings are very accurate and it publishes to the spreadsheet every 30 minutes.
On the other hand, the ESP8266 publishes new readings approximately every 28 to 29 minutes.
Updated on 27 March 2023
You can also set a threshold value, so your email notification is only sent if the temperature/humidity/pressure is above a certain value.
As an example, we’ll be using a BME280 sensor connected to an ESP32 or ESP8266 board.
You can modify the code provided to send readings from a different sensor or even use multiple boards.
This is a great way to send email notifications using the ESP32 or ESP8266 without relying on IFTTT or an SMTP server.
In order to build this project, you will:
This project is also a great addition to build upon our previous projects:
ESP32/ESP8266 Insert Data into MySQL Database using PHP and Arduino IDE
Visualize Your Sensor Readings from Anywhere in the World
I recommend using one of the following hosting services that can handle all the project requirements:
Bluehost (user-friendly with cPanel) : free domain name when you sign up for the 3-year plan.
I recommend choosing the unlimited websites option;
Digital Ocean : Linux server that you manage through a command line.
I only recommended this option for advanced users.
Those two services are the ones that I use and personally recommend, but you can use any other hosting service.
Any hosting service that offers PHP and MySQL will work with this tutorial.
If you don’t have a hosting account, I recommend signing up for Bluehost .
Get Hosting and Domain Name with Bluehost
When buying a hosting account, you’ll also have to purchase a domain name.
If you like our projects, you might consider signing up for one of the recommended hosting services, because you’ll be supporting our work.
Then, select the
Edit the newly created file (email-notification.php) and copy the following script:
<?php
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-send-email-notification/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
// Receiver Email Address (where to send email notification)
$email_address = " [emailprotected] ";
// Keep this API Key value to be compatible with the ESP code provided in the project page.
If you change this value, the ESP sketch needs to match
$api_key_value = "tPmAT5Ab3j7F9";
$api_key = $value1 = $value2 = $value3 = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$api_key = test_input($_POST["api_key"]);
if($api_key == $api_key_value) {
$value1 = test_input($_POST["value1"]);
$value2 = test_input($_POST["value2"]);
$value3 = test_input($_POST["value3"]);
// Email message
$email_msg = "Temperature: " .
$value1 .
"oC\nHumidity: " .
$value2 .
"%\nPressure: " .
$value3 .
"hPa";
// Use wordwrap() if lines are longer than 70 characters
$email_msg = wordwrap($email_msg, 70);
// Uncomment the next if statement to set a threshold
// ($value1 = temperature, $value2 = humidity, $value3 = pressure)
/*if($value1 < 24.0){
echo "Temperature below threshold, don't send email";
exit;
}*/
// send email with mail(receiver email address, email subject, email message)
mail($email_address, "[NEW] ESP BME280 Readings", $email_msg);
echo "Email sent";
}
else {
echo "Wrong API Key provided.";
}
}
else {
echo "No data posted with HTTP POST.";
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
View raw code
Before saving the file, you need to modify the $email_address variable with the receiver email address:
// Receiver Email Address (where to send email notification)
$email_address = " [emailprotected] ";
After adding the receiver email, save the file and continue with this tutorial.
If you try to access your domain name in the next URL path, you’ll see the following:
https://example.com/email-notification.php
If you see that message, it means that everything is being setup properly.
You can continue with this project.
| SCK (SCL Pin) | GPIO 22 |
| SDI (SDA pin) | GPIO 21 |
| SCK (SCL Pin) | GPIO 5 |
| SDI (SDA pin) | GPIO 4 |
If everything is working properly, this is what you should see in your Arduino IDE Serial Monitor:
Open your email client, you should have a new email with the subject “
To send a new email, press the ESP on-board RESET/ENABLE button to restart it and new readings will be sent out via email.
For a final application, I recommend using deep sleep to make the ESP send an email every X number of minutes/hours with low power consumption.
Read one of these guides to add deep sleep to your sketch:
ESP32 Deep Sleep with Arduino IDE and Wake Up Sources
ESP8266 Deep Sleep with Arduino IDE
Updated 14 May 2024
By the end of this tutorial, you’ll be able to build a dashboard as shown below to display all your sensor readings over time.
At the moment, dashboards are not compatible with InfluxdDB serverless .
You must use InfluxDB 2 (running on a Raspberry Pi, for example— see this post to set InfluxDB on Raspberry Pi .)
To get started with InfluxDB, read one of the following guides:
ESP32: Getting Started with InfluxDB
ESP8266 NodeMCU: Getting Started with InfluxDB
InfluxDB is an open-source high-performance time series database (TSDB) that can store large amounts of data per second.
Each data point you submit to the database is associated with a particular timestamp.
So, it is ideal for IoT datalogging projects like storing data from your weather station sensors.
You can run InfluxDB in InfluxDB Cloud , or locally on your laptop or Raspberry Pi .
“For a more in-depth introduction to InfluxDB, check the following tutorials before proceeding: ESP32: Getting Started with InfluxDB ESP8266: Getting Started with InfluxDBWhy use InfluxDB Cloud? It’s a fast, elastic, serverless real-time monitoring platform, dashboarding engine, analytics service and event and metrics processor.” https://www.influxdata.com/products/influxdb-cloud/
The page that opens allows you to create buckets, and it also shows some sample code to interface the ESP8266 or ESP32 boards with InfluxDB.
* if you’re running InfluxDB locally on a Raspberry Pi, the URL will be the Raspberry Pi IP address on port 8086.
For example 192.168.1.106:8086.
On this page, you can generate a new API token if needed.
At this moment, you should have saved the following:
InfluxDB Server URL
InfluxDB Organization
InfluxDB Bucket Name
API Token
Not familiar with the BME280 with the ESP32? Read this tutorial:
Not familiar with the BME280 with the ESP8266? Read this tutorial:
Follow the same procedure for the Adafruit BME280 library and Adafruit Unified Sensor library.
Your plaformio.ini file should look as follows (we also added a line to change the Serial Monitor baud rate to 115200).
monitor_speed = 115200
lib_deps =
tobiasschuerg/ESP8266 Influxdb@^3.12.0
adafruit/Adafruit BME280 Library@^2.2.2
adafruit/Adafruit Unified Sensor@^1.1.5
Now, go to your InfludDB account and go to the
Now, you can visualize your data.
Start by selecting the bucket you want.
Then, we need to add filters to select our data.
Select the
You can create a dashboard to show multiple data visualizations in different formats (gauges, histogram, single stat, etc.) or different data on the same page.
For example, multiple charts to show temperature, humidity, and pressure, and boxes to show the current measurements.
Repeat the same process for the other readings (humidity, and pressure).
You can also add a single stat to show the current values of each reading.
I have the ESP32 and ESP8266 running the same code simultaneously, so I created a dashboard that shows the readings of each board.
You can move your cells to different positions and organize the dashboard in a way that makes sense for you.
You can also customize the way the data is refreshed and how many data points you want to see (up to the past 30 days).
As an example, we’ll read the temperature using a DS18B20 temperature sensor.
You can use any other temperature sensor like DHT11/DHT22, BME280 or LM35 .
To better understand how this project works, we recommend reading these tutorials:
Input Data on HTML Form ESP32/ESP8266 Web Server (Arduino IDE)
ESP32 with DS18B20 (one sensor, multiple sensors, web server)
ESP8266 NodeMCU with DS18B20 (one sensor, multiple sensors, web server)
ESP32 Web Server or ESP8266 NodeMCU Web Server
The ESP32/ESP8266 hosts a web server that shows the latest temperature readings from a DS18B20 temperature sensor.
There’s an input field to set up a temperature threshold value.
When the temperature goes above the threshold, an output will be automatically turned on.
You can invert this logic depending on your project application.
When the temperature goes below the threshold, the output will be turned off.
The system can be activated or deactivated through the web server.
If you choose to deactivate the system, the output will keep its state, no matter the temperature value.
The following image shows how the web server page looks like.
To follow this tutorial you need the following parts:
ESP32 (read Best ESP32 boards ) or ESP8266 (read Best ESP8266 boards )
LED
220 Ohm resistor
DS18B20 temperature sensor (waterproof version )
4.7k Ohm resistor
Jumper wires
Breadboard
Open a browser and type the ESP IP address.
A similar web page should load with the default values (defined in your code):
If the arm trigger is enabled (checkbox ticked) and if the temperature goes above the threshold, the LED should turn on (output is set to HIGH).
After that, if the temperature goes below the threshold, the output will turn off.
You can use the web page input fields to change the threshold value or to arm and disarm controlling the output.
For any change to take effect, you just need to press the “Submit” button.
At the same time, you should get the new input fields in the Serial Monitor.
The ESP32/ESP8266 boards will be programmed using Arduino IDE.
So make sure you have these boards installed:
Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)
Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)
In this tutorial you’ll learn how to password protect your web server;
When you try to access the web server page on the ESP IP address, a window pops up asking for a username and password;
To get access to the web server page, you need to enter the right username and password (defined in the ESP32/ESP8266 sketch);
There’s a logout button on the web server.
If you click the logout button, you’ll be redirected to a logout page.
Then, close all web browser tabs to complete the logout process;
You can only access the web server again if you login with the right credentials;
If you try to access the web server from a different device (on the local network) you also need to login with the right credentials (even if you have a successful login on another device);
The authentication is not encrypted.
After typing the right username and password, you should get access to the web server.
You can play with the web server and see that it actually controls the ESP32 or ESP8266 on-board LED.
In the web server page, there’s a logout button.
If you click that button, you’ll be redirected to a logout page as shown below.
If you click the “return to homepage” link, you’ll be redirected to the main web server page.
If you’re using Google Chrome, you’ll need to enter the username and password to access the web server again.
If you’re using Firefox, you need to close all web browser tabs to completely logout.
Otherwise, if you go back to the main web server page, you’ll still have access.
So, we advise that you close all web browser tabs after clicking the logout button.
You also need to enter the username and password if you try to get access using a different device on the local network, even though you have access on another device.
The ESP32/ESP8266 boards will be programmed using Arduino IDE.
So make sure you have these boards installed:
Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)
Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)
The ESP32 or ESP8266 hosts a web server that you can access to control an output;
The output’s default state is LOW, but you can change it depending on your project application;
There’s a button that acts like a momentary switch:
if you press the button, the output changes its state to HIGH as long as you keep holding the button;
once the button is released, the output state goes back to LOW.
Open a browser on your local network, and type the ESP IP address.
You should have access to the web server as shown below.
The on-board LED stays on as long as you keep holding down the button on the web page.
When you release the button, the LED goes back to its default state (LOW).
Watch the next quick video for a live demonstration:
The ESP32 or ESP8266 hosts a web server that allows you to control the state of an output;
The current output state is displayed on the web server;
The ESP is also connected to a physical pushbutton that controls the same output;
If you change the output state using the physical puhsbutton, its current state is also updated on the web server.
In summary, this project allows you to control the same output using a web server and a push button simultaneously.
Whenever the output state changes, the web server is updated.
Open a browser on your local network, and type the ESP IP address.
You should have access to the web server as shown below.
You can toggle the button on the web server to turn the LED on.
You can also control the same LED with the physical pushbutton.
Its state will always be updated automatically on the web server.
Watch the next quick video for a live demonstration:
The ESP32/ESP8266 boards will be programmed using Arduino IDE.
So make sure you have these boards installed:
Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)
Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)
The ESP32/ESP8266 hosts a web server that allows you to control an output with a pulse;
The web server contains a slider that allows you to define the pulse width (how many seconds the output should be HIGH);
There’s an ON/OFF button.
Set it to ON to send the pulse.
After that, you’ll see a timer decreasing for the duration of the pulse width;
When the timer is over, the output is set to LOW, and the web server button goes back to OFF state;
This web server can be useful to control devices that need a pulse to activate like garage door openers, for example.
Drag the slider to adjust the pulse width, and then, click the ON/OFF button.
The output (in this case GPIO 2 – built-in LED) will stay on for the period of time you’ve set on the slider.
Watch the next quick video for a live demonstration:
Throughout this article we’ll cover the following subjects:
how to put the ESP32 in deep sleep mode;
wake up the ESP32 by changing the value of one GPIO (with a pushbutton) using the ext0 method;
wake up the ESP32 using several GPIOs using the ext1 method;
identify which GPIO caused the wake up.
To learn more about deep sleep and other wake up sources, you can follow the next tutorials:
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
Press the pushbutton to wake up the ESP32.
Try this several times, and see the boot count increasing in each button press.
Using this method is useful to wake up your ESP32 using a pushbutton, for example, to make a certain task.
However, with this method you can only use one GPIO as wake up source.
What if you want to have different buttons, all of them wake up the ESP, but do different tasks? For that you need to use the ext1 method.
3.
Copy the Hex number to the BUTTON_PIN_BITMASK variable, and you should get:
#define BUTTON_PIN_BITMASK 0x200000000 // 2^33 in hex

Open the Serial Monitor at a baud rate of 115200.
Press the pushbuttons to wake up the ESP32.
You should get something similar on the serial monitor.
In a later tutorial, you’ll learn how to create a Firebase web app that you can access from anywhere to monitor and control your ESP32 using firebase’s realtime database:
ESP32 with Firebase – Creating a Web App
We have a similar tutorial for the ESP8266 board: Getting Started with Firebase (Realtime Database)
Firebase is Google’s mobile application development platform that helps you build, improve, and grow your app.
It has many services used to manage data from any android, IOS, or web application.
The following paragraph clearly explains the advantages of using Firebase:
“Firebase is a toolset to “build, improve, and grow your app”, and the tools it gives you cover a large portion of the services that developers would normally have to build themselves but don’t really want to build because they’d rather be focusing on the app experience itself.
This includes things like analytics, authentication, databases, configuration, file storage, push messaging, and the list goes on.
The services are hosted in the cloud and scale with little to no effort on the part of the developer.”
This paragraph was taken from this article , and we recommend that you read that article if you want to understand better what firebase is and what it allows you to do.
You can use the ESP32 to connect and interact with your Firebase project, and you can create applications to control the ESP32 via Firebase from anywhere in the world.
In this tutorial, we’ll create a Firebase project with a realtime database, and we’ll use the ESP32 to store and read data from the database.
The ESP32 can interact with the database from anywhere in the world as long as it is connected to the internet.
This means that you can have two ESP32 boards in different networks, with one board storing data and the other board reading the most recent data, for example.
In a later tutorial, we’ll create a web app using Firebase that will control the ESP32 to display sensor readings or control outputs from anywhere in the world.
Disable the option Enable Google Analytics for this project as it is not needed and click Create project.
It will take a few seconds setting up your project.
Then, click Continue when it’s ready.
There are several authentication methods like email and password, Google Account, Facebook account, and others.
For testing purposes, we can select the Anonymous user (require authentication without requiring users to sign in first by creating temporary anonymous accounts).
Enable that option and click Save.
Select your database location.
It should be the closest to your location.
Set up security rules for your database.
For testing purposes, select Start in test mode.
In later tutorials you’ll learn how to secure your database using database rules.
Your database is now created.
You need to copy and save the database URL—highlighted in the following image—because you’ll need it later in your ESP32 code.
The Realtime Database is all set.
Now, you also need to get your project API key.
Copy the API Key to a safe place because you’ll need it later.
Now, you have everything ready to interface the ESP32 with the database.
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
Now, you’re all set to start programming the ESP32 board to interact with the database.
Copy the following code to your Arduino IDE.
This sketch inserts an int and a float number into the database every 15 seconds.
This is a simple example showing you how to connect the ESP32 to the database and store data.
This is also compatible with ESP8266 boards .
Go to your project’s Firebase Realtime database, and you’ll see the values saved on the different node paths.
Every 15 seconds, it saves a new value.
The database blinks when new values are saved.
Congratulations! You’ve successfully stored data in Firebase’s realtime database using the ESP32.
In the next section, you’ll learn to read values from the different database’s node paths.
In this section, you’ll learn how to read data from the database.
We’ll read the data stored in the previous section.
Remember that we saved an int value in the test/int path and a float value in the test/float path.
The following example reads the values stored in the database.
Upload the following code to your board.
You can use the same ESP32 board or another board to get the data posted by the previous ESP32.
Complete the following tutorial before proceeding:
Getting Started with ESP32 with Firebase (Realtime Database)
Here are the major steps to complete this tutorial.
Creating Firebase Project —we recommend using the Firebase project from this previous tutorial .
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU with Firebase – Creating a Web App
Click on the installation wizard to start the installation and follow all the steps to complete the installation.
Accept the agreement and press the
Select the following options and click
Press the
Finally, click
Open VS Code, and you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
After downloading the Visual Studio Code application file, you’ll be prompted with the following message.
Press the “
Or open your Downloads folder and open Visual Studio Code.
After that, you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
Save the installation file:
To install it, open a Terminal window, navigate to your Downloads folder and run the following command to install VS Code.
$ cd Downloads
~/Downloads $ sudo apt install ./code_1.49.1-1600299189_amd64.deb
When the installation is finished, VS Code should be available in your applications menu.
Open VS Code, and you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
As you can see in the error message, there’s an error message related to the firebase.ps1 file on the C: \Users\username\AppData\Roaming\npm path.
Go to that path and delete the firebase.ps1 file.
Go back to VS Code, and rerun the following command.
The index.html file contains some HTML text to build a web page.
For now, leave the default HTML text.
The idea is to replace that with your own HTML text to build a custom web page for your needs.
We’ll do that later in this tutorial.
Now, you need to get your web app URL to access it.
Click
Congratulations, you’ve set up your Firebase App project correctly.
Now, let’s change the files in the public folder to show your own web page instead of that one.
Go to your App URL.
You’ll see the readings being updated every 15 seconds.
The App updates the web page any time the ESP32 writes a new value.
In your Firebase Console, you can go to your project page, and check that new values are being written into the database every 15 seconds.
Congratulations! You’ve created a Firebase Web App to interface with the ESP32.
You don’t want this to happen.
You want the ESP32 to remember what was happening before losing power and return to the last state.
To solve this problem, you can save the lamp’s state in the flash memory.
Then, you just need to add a condition at the beginning of your sketch to check the last lamp state, and turn the lamp on or off accordingly.
The following figure shows what we’re going to do:
We have a similar article for the ESP8266: 20 Free Guides for Sensors and Modules [ESP8266] .
Here’s a quick list of the sensors/modules:
TheDS18B20 temperature sensoris a one-wire digital temperature sensor.
This means that it just requires one data line (and GND) to communicate with your ESP32.
Each DS18B20 temperature sensor has a unique 64-bit serial code.
This allows you to wire multiple sensors to the same data wire.
So, you can get temperature from multiple sensors using just one GPIO.
The DS18B20 temperature sensor is also available inwaterproof version.
To get started, you can follow the next tutorials:
A K-type thermocouple is a type of temperature sensor with a wide measurement range like 200 to 1260oC (326 to 2300oF).
To get the temperature from the thermocouple we need a thermocouple amplifier.
We use the MAX6675 amplifier that is sold together with the thermocouple, but you can use any other amplifier, like the MAX31855.
To get started, follow the next tutorial:
The DHT11 and DHT22 sensors are used to measure temperature and relative humidity.
These sensors contain a chip that does analog to digital conversion and spits out a digital signal with the temperature and humidity.
This makes them very easy to use with any microcontroller.
To get started, follow the next tutorials:
The BME280 sensor module reads barometric pressure, temperature, and humidity.
Because pressure changes with altitude, you can also estimate altitude.
There are several versions of this sensor module: some can communicate using only I2C communication protocol, and others have the additional option to use the SPI communication protocol.
We usually use the I2C protocol with this sensor.
This sensor is very versatile and we use it in many of our tutorials.
To get started, follow the next tutorials:
The BME680 is an environmental sensor that combines gas, pressure, humidity, and temperature sensors.
The gas sensor can detect a broad range of gases like volatile organic compounds (VOC).
For this reason, the BME680 can be used in indoor air quality control.
To get started, follow the next tutorials:
The BMP388 is a precise, low-power, low-noise absolute barometric pressure sensor that measures absolute pressure and temperature.
Because pressure changes with altitude, we can also estimate altitude with great accuracy.
For this reason, this sensor is handy for drone navigation and other applications like vertical velocity calculation; internet of things; weather forecast, and weather stations; health care applications; fitness applications; and much more.
To get started, follow the next tutorial:
The BMP180 is a digital pressure sensor and it measures the absolute pressure of the air around it.
It features a measurement range from 300 to 1100hPa with an accuracy down to 0.02 hPa.
Because temperature affects the pressure, the sensor comes with a temperature sensor to give temperature compensated pressure readings.
Additionally, because the pressure changes with altitude, you can also estimate the altitude based on the current pressure measurement.
The sensor communicates with a microcontroller using I2C communication protocol.
To get started, follow the next tutorial:
The BH1750 is a 16-bit ambient light sensor that communicates via I2C protocol.
It outputs luminosity measurements in lux (SI-derived unit of illuminance).
It can measure a minimum of 1 lux and a maximum of 65535 lux.
It can be used in a wide variety of projects.
For example: to detect if it is day or night; to adjust or turn on/off LED’s brightness accordingly to ambient light; to adjust LCDs and screen’s brightness; to detect if an LED is lit; etc.
To get started, follow the next tutorial:
A TDS meter indicates the total dissolved solids like salts, minerals, and metals, in a solution.
This parameter can be used to give you an idea of water quality and compare water from different sources.
One of the main applications of a TDS meter is aquarium water quality monitoring.
To get started, follow the next tutorial:
The PIR motion sensor is ideal to detect movement.
PIR stands for “Passive Infrared” and it measures infrared light from objects in its field of view.
So, it can detect motion based on changes in infrared light in the environment.
It is ideal to detectif a human or animal has moved in or out of the sensor range.
Get started with the following tutorials:
A magnetic contact switch is a reed switch encased in a plastic shell so that you can easily apply it on a door, a window, or a drawer to detect if it is open or closed.
We have several tutorials with the ESP32 that use a reed switch and send notifications when the door is opened or closed:
ESP32 Door Status Monitor with Telegram Notifications
ESP32 Door Status Monitor with Email Notifications (IFTTT)
Get a magnetic reed switch.
The HC-SR04 ultrasonic sensor uses sonar to determine the distance to an object.
This sensor reads from 2cm to 400cm (0.8inch to 157inch) with an accuracy of 0.3cm (0.1inches), which is good for most hobbyist projects.
In addition, this particular module comes with ultrasonic transmitter and receiver modules.
Get started with one of the following tutorials:
The MPU-6050 IMU (Inertial Measurement Unit) is a 3-axis accelerometer and 3-axis gyroscope sensor.
The accelerometer measures the gravitational acceleration and the gyroscope measures the rotational velocity.
Additionally, this module also measures temperature.
This sensor is ideal to determine the orientation of a moving object.
To get started, follow the next tutorial:
The RCWL-0516 is a small, inexpensive sensor that uses microwave radar to detect the presence of moving objects.
The RCWL-0516 sensor has a single output pin that goes HIGH when it detects movement.
It outputs LOW when no motion is detected.
This sensor is many times used as an alternative to the PIR motion sensor.
Get started with the following tutorial:
ESP32 with RCWL-0516 Microwave Radar Proximity Sensor (Arduino IDE)
Get an RCWL-0516 Microwave Radar Proximity Sensor .
The microSD card module allows you to interface the ESP32 with a microSD card.
You can use the microSD card with the ESP32 to create, write, read, and delete files.
It can be very useful for datalogging, to save configuration files or save files to serve to clients via a web server.
To get started, follow the next tutorial:
A potentiometer, also referred to as a pot, is a manually adjustable resistor that can be used in numerous applications: adjust the speed of a DC motor, adjust the position of a stepper or servo motor, adjust threshold values, adjust light intensity, and much more.
To get a value from a potentiometer, you need to know how to read analog signals with the ESP32.
Get started with the following tutorials:
A relay is an electrically operated switch and like any other switch, it that can be turned on or off, letting the current go through or not.
It can be controlled with low voltages, like the 3.3V provided by the ESP32 GPIOs, and allows us to control high voltages like 12V, 24V, or mains voltage (230V in Europe and 120V in the US).
Using a relay with the ESP32 is a great way to control AC household appliances remotely.
Get started with the following tutorials:
The load cell you see in the picture above is a strain gauge load cell.
A strain gauge is an electrical sensor that measures force or strain on an object.
The resistance of the strain gauge varies when an external force is applied to an object, which results in a deformation of the object’s shape (in this case, the metal bar).
The change of the resistance is proportional to the load applied, which allows us to calculate the weight of objects.
Get started with the following tutorial:
Theorganic light-emitting diode(OLED) display is a monocolor display that doesn’t require backlight, which results in a very nice contrast in dark environments.
Additionally, its pixels consume energy only when they are on, so the OLED display consumes less power when compared with other displays.
It’s available with different drivers, but we recommend getting the one with the SSD1306 driver, which is the most supported.
There is also a wide variety of OLED sizes.
We usually use the 0.96-inch display with 128×64 pixels.
There are also ESP32 boards with a built-in OLED display.
This is very useful because you don’t need any extra circuitry if you want to add a physical visual interface to your project: ESP32 Built-in OLED Board (Wemos Lolin32): Pinout, Libraries and OLED Control .
The simplest and cheapest display screen around is the liquid crystal display (LCD).
LCDs are found in everyday electronics devices like vending machines, calculators, parking meters, and printers, and are ideal for displaying text or small icons.
LCDs are measured according to the number of rows and columns of characters that fit on the screen.
You’ll find sizes ranging from 8×1 to 40×4.
A 16×2 LCD can display 2 rows of 16 characters each and this is the one we use most in our projects.
We recommend getting one that supports I2C because it makes wiring and coding even easier.
Get started with the following tutorial:
LED strips are just amazing, and there are a wide variety of LED strips to choose from.
They can be analog, or digital, and vary in the density and number of LEDs, power supply, etc.
To learn more about the main differences between LED strips, I recommend taking a look at the following article: What’s the Best LED Strip For Your Project?
Analog LED strips have their LEDs wired in parallel.
The whole strip works as a giant RGB LED.
So, you can light up your whole strip in many different colors, but you can’t control LEDs individually.
This means your strip can only be one color at a time.
This type of LED strips are cheaper than the digital ones and easier to use.
You can follow the next tutorial that shows how to use those LED strips:
LoRa is a wireless data communication technology that uses a radio modulation technique that can be generated by Semtech LoRa transceiver chips.
This modulation technique allows long-range communication of small amounts of data (which means a low bandwidth), and high immunity to interference while minimizing power consumption.
So, it allows long-distance communication with low power requirements.
To use LoRa in your projects, you can use a transceiver like the RFM95 or use an ESP32 with a built-in LoRa transceiver module .
Get started with the following tutorials:
The I2C communication protocol allows you to communicate with multiple I2C devices on the same I2C bus as long as each device has a unique I2C address.
However, it will not work if you want to connect multiple I2C devices with the same address.
The TCA9548A I2C multiplexer allows you to communicate with up to 8 I2C devices with the same I2C bus.
The multiplexer communicates with a microcontroller using the I2C communication protocol.
Then, you can select which I2C bus on the multiplexer you want to address.
Get started with the following tutorial:
Learn how to control a servo motor with the ESP32 remotely using a web server:
ESP32 Servo Motor Web Server with Arduino IDE
Get a micro servo motor .
Learn how to control a DC motor (speed and direction) with the ESP32 using the L298N motor driver.
To get started, follow the next tutorial:
A stepper motor is a brushless DC electric motor that divides a full rotation into a number of steps.
It moves one step at a time, and each step is the same size.
This allows us to rotate the motor at a precise angle to a precise position.
The stepper motor can rotate clockwise or counterclockwise.
To get started, follow the next tutorial:
A hall effect sensor can detect variations in the magnetic field in its surroundings.
The greater the magnetic field, the greater the sensor’s output voltage.
The hall effect sensor can be combined with a threshold detection to act as a switch, for example.
Additionally, hall effect sensors are mainly used to:
Detect proximity;
Calculate positioning;
Count the number of revolutions of a wheel;
Detect a door closing;
And much more.
Or decreasing depending on the magnet pole that is facing the sensor:
The closer the magnet is to the sensor, the greater the absolute values are.
This tutorial covers the following topics:
The next picture shows the other side of the sensor.
| 5V DC | |
| 15 mA | |
| 40 kHz | |
| 4 meters | |
| 2 cm | |
| 15o | |
| 0.3 cm | |
| 10uS TTL pulse | |
| TTL pulse proportional to the distance range | |
| 45mm x 20mm x 15mm |
| VCC | Powers the sensor (5V) |
| Trig | Trigger Input Pin |
| Echo | Echo Output Pin |
| GND | Common GND |
Taking into account the sound’s velocity in the air and the travel time (time passed since the transmission and reception of the signal) we can calculate the distance to an object.
Here’s the formula:
distance to an object = ((speed of sound in the air)*time)/2
speed of sound in the air at 20oC (68oF) =
To complete this tutorial you need the following parts:
HC-SR04 Ultrasonic Sensor
ESP32 (read Best ESP32 development boards )
Breadboard
Jumper wires
| VCC | VIN |
| Trig | GPIO 5 |
| Echo | GPIO 18 |
| GND | GND |
After uploading, open the Serial Monitor at a baud rate of 115200.
Press the on-board RST button to restart the board and it will start printing the distance to the closest object on the Serial Monitor.
Something as shown in the picture below.
In this section, we’ll show you a simple example with the ESP32 that displays the distance on an I2C OLED display.
To better understand how the project works, we recommend taking a look at our ESP32 tutorial with the I2C OLED display .
Learn more about the OLED display with the ESP32: ESP32 OLED Display with Arduino IDE
After installing the SSD1306 library from Adafruit, type “
After installing the libraries, restart your Arduino IDE.
Then, simply copy the following code to your Arduino IDE and upload the code to the board.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-hc-sr04-ultrasonic-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
const int trigPin = 5;
const int echoPin = 18;
//define sound speed in cm/uS
#define SOUND_SPEED 0.034
#define CM_TO_INCH 0.393701
long duration;
int distanceCm;
int distanceInch;
void setup() {
Serial.begin(115200);
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(500);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculate the distance
distanceCm = duration * SOUND_SPEED/2;
// Convert to inches
distanceInch = distanceCm * CM_TO_INCH;
// Prints the distance in the Serial Monitor
Serial.print("Distance (cm): ");
Serial.println(distanceCm);
Serial.print("Distance (inch): ");
Serial.println(distanceInch);
display.clearDisplay();
display.setCursor(0, 25);
//Display distance in cm
display.print(distanceCm);
display.print(" cm");
// Display distance in inches
/* display.print(distanceInch);
display.print(" in");*/
display.display();
delay(500);
}
View raw code
You can watch a quick video demonstration:
Throughout this article, we’ll cover the following methods to save data using the ESP32:
Using a microSD card with the ESP32 is a great way to save data permanently.
You can save big amounts of data in txt or in other formats—as much as the microSD card size allows you to.
You can also save pictures if you’re using an ESP32-CAM .
To interface a microSD card with the ESP32, you can use a microSD card module that communicates with the board via SPI communication protocol.
These modules are usually pretty cheap.
You can check some microSD card modules here .
Some ESP32 development boards already come with a built-in microSD card slot, so you won’t need any extra circuitry or hardware.
We have a complete guide showing how to interface a microSD card with the ESP32 and how to handle files—read, write, create, delete, append, and much more.
ESP32: Guide for MicroSD Card Module using Arduino IDE
If you want a specific datalogging example with sensors, we also have the following projects (you can easily modify the projects to use other sensors):
Altimeter Datalogger: ESP32 with BMP388, MicroSD Card Storage and OLED Display
ESP32 Data Logging Temperature to MicroSD Card
The ESP32 contains a Serial Peripheral Interface Flash File System (SPIFFS).
SPIFFS is a lightweight filesystem created for microcontrollers with a flash chip (like the ESP32) that allows you to store files in the flash memory.
Here are some tutorials using the ESP32 filesystem:
Install ESP32 Filesystem Uploader in Arduino IDE
ESP32 Web Server using SPIFFS (SPI Flash File System)
SPIFFS lets you access the flash memory like you would do in a normal filesystem in your computer, but simpler and more limited.
You can read, write, close, and delete files.
The SPIFFS library that allows you to interact with the flash chip doesn’t support directories, so everything is saved on a flat structure.
LittleFS is a new filesystem that you can use with the ESP32 that supports directories, is faster, and has some other improvements over SPIFFS.
You can create files to save data on the ESP32 filesystem as you would do with a microSD card.
The advantage is that you don’t need any extra hardware.
However, it’s not appropriate for saving big amounts of data or for long-term datalogging applications and you’re limited to the size dedicated to the filesystem on the ESP2 partition.
Firebase is Google’s mobile application development platform that provides several tools to save data:
We prefer using the Realtime Database for datalogging projects, because, in our opinion, it’s easier to handle and program than Cloud Firestore.
We have the following guides to learn how to get started datalogging using Firebase Realtime Database.
ESP32: Getting Started with Firebase (Realtime Database)
ESP32 Data Logging to Firebase Realtime Database
ESP32/ESP8266 Firebase: Send BME280 Sensor Readings to the Realtime Database
Firebase Cloud Storage is another service that can be used to save files.
Imagine that you have several files saved on the microSD card.
The ESP32 can connect once a day to the internet to backup those files on Firebase Cloud Storage.
We also have used Firebase Cloud Storage to store pictures taken with the ESP32-CAM:
ESP32-CAM Save Picture in Firebase Storage
InfluxDB is one of my favorite databases for datalogging.
InfluxDB is an open-source high-performance time series database (TSDB) that can store large amounts of data per second.
Each data point you submit to the database is associated with a particular timestamp.
So, it is ideal for IoT datalogging projects like storing data from your weather station sensors.
You can run InfluxDB in InfluxDB Cloud , or locally on your laptop or Raspberry Pi .
InfluxDB cloud is a great alternative because it hosts your data that can be accessed from anywhere.
However, the free cloud plan only lets you save data until the last 30 days.
Depending on your project application, that might be a good alternative.
Or if you’re willing to pay for a premium plan, InfluxDB cloud might be the best solution.
To get started datalogging with InfluxDB and the ESP32, you can follow the next tutorials.
ESP32: Getting Started with InfluxDB
ESP32/ESP8266: Send BME280 Sensor Readings to InfluxDB
Besides being a database, InfluxDB also allows you to build dashboards with different types of graphs, charts, gauges, and more to display your data.
You can do all of this using their interface.
You don’t need to write any code to build the charts or dashboard.
Deta Base is a NoSQL database.
It is unlimited, free, and easy to use.
Additionally, it requires minimal setup.
So, it’s perfect for your hobbyist projects and prototyping.
It offers a UI through which you can easily see, query, update and delete records in the database.
The biggest advantage of Deta Base over other database solutions is that it requires very little setup.
Once you sign up for Deta Base, it’s ready to use.
As with Firebase, you can create your own web applications to interact with the database.
If you want to learn how to use Deta Base with the ESP32, you can follow our guide:
ESP32: Getting Started with Deta Base (Unlimited and Free Database for Developers)
ThingSpeak is an IoT platform in which you can create channels to store data.
It provides visualization tools and different widgets to display your data like charts, gauges, or numeric displays.
The submitted data is also associated with a timestamp, which is useful if you want to display it on charts to see how it behaves over time.
You can have multiple devices publishing data to your Thingspeak account.
Usually, each device will require a channel.
The free plan is limited to four channels.
In my opinion, the visual interface is easy to use, but it allows very little customization when compared with the tools provided by InfluxDB.
However, it is perfect if you just want a simple visualization without having to worry about formatting details (like series colors, charts background colors, etc.).
The data is stored in the cloud, so you can access your data anywhere from your account,
We have two different tutorials that show different methods to publish data to Thingspeak.
The following shows how to make an HTTP POST request with data to Thingspeak services (you need to write the request manually on the code):
ESP32 HTTP POST with Arduino IDE (ThingSpeak)
An easier way to publish data to Thingspeak with the ESP32 is to use a library.
You just need to call a function and pass as an argument the data you want to send.
ESP32 Publish Sensor Readings to ThingSpeak (easiest way)
Another great alternative to log data with the ESP32 is to use Google Sheets.
Then, you can analyze, manage, and display your data using the features provided in Google Sheets.
You can have access to your data from anywhere using your Google account.
This is a good method if you need to store data that needs processing later on.
We have a guide showing how to log sensor readings to Google Sheets using IFTTT services.
The advantage of using IFTTT services is that you don’t need to create any scripts or additional configurations in your Google account.
However, it has some limitations in the number of requests you can make with the free account and with how much information you can save at once.
Here’s the tutorial:
ESP32 Publish Sensor Readings to Google Sheets
If you don’t want to rely on a third-party service to publish data to Google Sheets with the ESP32, you can use .
A great method to log data to Google Sheets is using a Google Service Account and the Google Sheets API.
A service account, identified by its unique email address, is a special kind of account that is typically used by an application or compute workload, like a Compute Engine instance, rather than being associated with a person.
Usinga GoogleService Account is one of the safest methods and is recommended byGoogleto interact with yourGoogleSheets.
Learn how to log data with the ESP32 to Google Sheets using a Google Service account and the Google Sheets API:
ESP32 Datalogging to Google Sheets (using Google Service Account)
You can install a MySQL Database on a cloud server and then, make requests with the ESP32 to publish and retrieve data.
This method is great for those who like programming, setting up their own servers, and want to have full control over their data storage.
If you’re already familiar with MySQL and PHP, you’ll certainly like this method.
The biggest disadvantage of this method is that you need to set up everything on your own from scratch which is easily prone to errors.
Additionally, you’ll need to pay for hosting and a domain name.
You can follow the next tutorials to set up a MySQL database on your own server and then, learn how to create a web page to display the data on charts:
ESP32/ESP8266 Insert Data into MySQL Database using PHP and Arduino IDE
Visualize Your Sensor Readings from Anywhere in the World (ESP32/ESP8266 + MySQL + PHP)
In this project, you’ll use that API to request the day’s weather forecast for your chosen location.
Learning to use APIs is a great skill because it allows you access to a wide variety of constantly changing information, such as current stock prices, currency exchange rates, the latest news, traffic updates, tweets, and much more.
On the
For demonstration purposes, we’re requesting new data every 10 seconds.
However, for a long term project you should increase the timer or check the API call limits per hour/minute to avoid getting blocked/banned.
Open your newly created channel and select the
Your ThingSpeak Dashboard (under the Private View tab) should be receiving new readings every 10 seconds.
For a final application, you might need to increase the timer or check the API call limits per hour/minute to avoid getting blocked/banned.
Go to
Copy the next sketch to your Arduino IDE (type your SSID and password):
/*
Rui Santos
Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-get-post-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
//Your Domain name with URL path or IP address with path
const char* serverName = "http://192.168.1.106:1880/get-sensor";
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 5 seconds (5000)
unsigned long timerDelay = 5000;
String sensorReadings;
float sensorReadingsArr[3];
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
Serial.println("Timer set to 5 seconds (timerDelay variable), it will take 5 seconds before publishing the first reading.");
}
void loop() {
//Send an HTTP POST request every 10 minutes
if ((millis() - lastTime) > timerDelay) {
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
sensorReadings = httpGETRequest(serverName);
Serial.println(sensorReadings);
JSONVar myObject = JSON.parse(sensorReadings);
// JSON.typeof(jsonVar) can be used to get the type of the var
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
return;
}
Serial.print("JSON object = ");
Serial.println(myObject);
// myObject.keys() can be used to get an array of all the keys in the object
JSONVar keys = myObject.keys();
for (int i = 0; i < keys.length(); i++) {
JSONVar value = myObject[keys[i]];
Serial.print(keys[i]);
Serial.print(" = ");
Serial.println(value);
sensorReadingsArr[i] = double(value);
}
Serial.print("1 = ");
Serial.println(sensorReadingsArr[0]);
Serial.print("2 = ");
Serial.println(sensorReadingsArr[1]);
Serial.print("3 = ");
Serial.println(sensorReadingsArr[2]);
}
else {
Serial.println("WiFi Disconnected");
}
lastTime = millis();
}
}
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// If you need Node-RED/server authentication, insert user and password below
//http.setAuthorization("REPLACE_WITH_SERVER_USERNAME", "REPLACE_WITH_SERVER_PASSWORD");
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "{}";
if (httpResponseCode>0) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
}
else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
// Free resources
http.end();
return payload;
}
View raw code
For debugging purposes, the requested information is also printed in the Node-RED debug window.
Copy the next sketch to your Arduino IDE (type your SSID and password):
/*
Rui Santos
Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-get-post-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
//Your Domain name with URL path or IP address with path
const char* serverName = "http://192.168.1.106:1880/update-sensor";
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 5 seconds (5000)
unsigned long timerDelay = 5000;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
Serial.println("Timer set to 5 seconds (timerDelay variable), it will take 5 seconds before publishing the first reading.");
}
void loop() {
//Send an HTTP POST request every 10 minutes
if ((millis() - lastTime) > timerDelay) {
//Check WiFi connection status
if(WiFi.status()== WL_CONNECTED){
WiFiClient client;
HTTPClient http;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// If you need Node-RED/server authentication, insert user and password below
//http.setAuthorization("REPLACE_WITH_SERVER_USERNAME", "REPLACE_WITH_SERVER_PASSWORD");
// Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
// Data to send with HTTP POST
String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&value1=24.25&value2=49.54&value3=1005.14";
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);
// If you need an HTTP request with a content type: application/json, use the following:
//http.addHeader("Content-Type", "application/json");
//int httpResponseCode = http.POST("{\"api_key\":\"tPmAT5Ab3j7F9\",\"sensor\":\"BME280\",\"value1\":\"24.25\",\"value2\":\"49.54\",\"value3\":\"1005.14\"}");
// If you need an HTTP request with a content type: text/plain
//http.addHeader("Content-Type", "text/plain");
//int httpResponseCode = http.POST("Hello, World!");
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
// Free resources
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
lastTime = millis();
}
}
View raw code
And in this example, those values are also sent to 3 Gauges and are displayed in Node-RED Dashboard:
http://raspberry-pi-ip-address:1880/ui
Open your newly created channel and select the
Your ThingSpeak Dashboard should be receiving new random readings every 10 seconds.
For a final application, you might need to increase the timer or check the API call limits per hour/minute to avoid getting blocked/banned.
This means you can trigger an event when something happens.
In this example, the applet sends three random values to your email when the ESP32 makes a request.
You can replace those random values with useful sensor readings .
2.
Click on the “
3.
Choose the “
5.
Then, select
A page showing your unique API key will show up.
Save your API key because you’ll need it later.
3.
Fill the “To trigger an Event with 3 JSON values” section with the event name created previously, in our case
4.
The event should be successfully triggered, and you’ll get a green message saying “
Go to your email account, and you should get a new email from IFTTT with three random values.
In this case: 38, 20 and 13.
For demonstration purposes, we’re publishing new data every 10 seconds.
However, for a long term project you should increase the timer or check the API call limits per hour/minute to avoid getting blocked/banned.
2.
Connect the Full Band LTE antenna to the correct antenna port as illustrated in the following image:
Copy the following code to your Arduino IDE.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-https-requests-sim-card-sim7000g/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Based on the library example: github.com/vshymanskyy/TinyGSM/blob/master/examples/HttpsClient/HttpsClient.ino
*/
// Select your modem
#define TINY_GSM_MODEM_SIM7000SSL
#define TINY_GSM_RX_BUFFER 1024 // Set RX buffer to 1Kb
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
#define SerialAT Serial1
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
// #define LOGGING // <- Logging is for the HTTP library
// Add a reception delay, if needed.
// This may be needed for a fast processor at a slow baud rate.
// #define TINY_GSM_YIELD() { delay(2); }
// set GSM PIN, if any
#define GSM_PIN ""
// flag to force SSL client authentication, if needed
// #define TINY_GSM_SSL_CLIENT_AUTHENTICATION
// Set your APN Details / GPRS credentials
const char apn[] = "";
const char gprsUser[] = "";
const char gprsPass[] = "";
// Server details
const char server[] = "gist.githubusercontent.com";
const char resource[] = "/RuiSantosdotme/7db8537cef1c84277c268c76a58d07ff/raw/d3fe4cd6eff1ed43e6dbd1883ab7eba8414e2406/gistfile1.txt";
const int port = 443;
TinyGsm modem(SerialAT);
TinyGsmClientSecure client(modem);
HttpClient http(client, server, port);
// LilyGO T-SIM7000G Pinout
#define UART_BAUD 115200
#define PIN_DTR 25
#define PIN_TX 27
#define PIN_RX 26
#define PWR_PIN 4
#define SD_MISO 2
#define SD_MOSI 15
#define SD_SCLK 14
#define SD_CS 13
#define LED_PIN 12
void modemPowerOn(){
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, LOW);
delay(1000);
digitalWrite(PWR_PIN, HIGH);
}
void modemPowerOff(){
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, LOW);
delay(1500);
digitalWrite(PWR_PIN, HIGH);
}
void modemRestart(){
modemPowerOff();
delay(1000);
modemPowerOn();
}
void setup() {
// Set Serial Monitor baud rate
SerialMon.begin(115200);
delay(10);
// Set LED OFF
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
modemPowerOn();
SerialMon.println("Wait...");
// Set GSM module baud rate and Pins
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
delay(6000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
SerialMon.println("Initializing modem...");
modem.restart();
// modem.init();
String modemInfo = modem.getModemInfo();
SerialMon.print("Modem Info: ");
SerialMon.println(modemInfo);
// Unlock your SIM card with a PIN if needed
if (GSM_PIN && modem.getSimStatus() != 3) {
modem.simUnlock(GSM_PIN);
}
Serial.println("Make sure your LTE antenna has been connected to the SIM interface on the board.");
delay(10000);
}
void loop() {
modem.gprsConnect(apn, gprsUser, gprsPass);
SerialMon.print("Waiting for network...");
if (!modem.waitForNetwork()) {
SerialMon.println(" fail");
delay(10000);
return;
}
SerialMon.println(" success");
if (modem.isNetworkConnected()) {
SerialMon.println("Network connected");
}
SerialMon.print(F("Performing HTTPS GET request...
"));
http.connectionKeepAlive(); // Currently, this is needed for HTTPS
int err = http.get(resource);
if (err != 0) {
SerialMon.println(F("failed to connect"));
delay(10000);
return;
}
int status = http.responseStatusCode();
SerialMon.print(F("Response status code: "));
SerialMon.println(status);
if (!status) {
delay(10000);
return;
}
SerialMon.println(F("Response Headers:"));
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
SerialMon.println(" " + headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
// Shutdown
http.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
// Do nothing forevermore
while (true) {
delay(1000);
}
}
View raw code
Insert your SIM card pin, if you have it.
In my case, I disabled the pin.
#define GSM_PIN ""
Insert your apn details on the following lines:
// Set your APN Details / GPRS credentials
const char apn[] = "";
const char gprsUser[] = "";
const char gprsPass[] = "";
For example, in my case:
const char apn[] = "net2.vodafone.pt";
const char gprsUser[] = "vodafone";
const char gprsPass[] = "vodafone";
Go to
Finally, upload the code to your board.
Then, open the Serial Monitor at a baud rate of 115200.
Press the on-board RST button to restart the board.
Wait some time until the board connects to the network (in my case, it may take up to 2 minutes).
You should get something similar in your Serial Monitor—see the picture below.
You can see that it identifies the SIM7000G module and connects to the network successfully.
Finally, it establishes a connection to the example website, returns the “Random Nerd Tutorials” text and prints it in the response.
If you see something similar in your Arduino IDE Serial Monitor, it means the code is running successfully.
The following snippet is for debugging purposes, it prints the response header and content length.
SerialMon.println(F("Response Headers:"));
while (http.headerAvailable()) {
String headerName = http.readHeaderName();
String headerValue = http.readHeaderValue();
SerialMon.println(" " + headerName + " : " + headerValue);
}
int length = http.contentLength();
if (length >= 0) {
SerialMon.print(F("Content length is: "));
SerialMon.println(length);
}
if (http.isResponseChunked()) {
SerialMon.println(F("The response is chunked"));
}
The response body is the actual interesting part of the response.
The String body is what you can use to scrap some text or information from a website.
String body = http.responseBody();
SerialMon.println(F("Response:"));
SerialMon.println(body);
SerialMon.print(F("Body length is: "));
SerialMon.println(body.length());
In this case, it’s just a sample project, so we’ve returned some characters saying “Random Nerd Tutorials” in ASCII art.
In future projects, we’ll scrap useful information from websites.
You can easily modify this example to get data from other website by changing the URL and resource.
Finally, stop the http connection and disconnect the GPRS modem from the Internet.
http.stop();
SerialMon.println(F("Server disconnected"));
modem.gprsDisconnect();
SerialMon.println(F("GPRS disconnected"));
That’s it, those are the most relevant code parts of this sketch.
Using an ESP8266 board? Check this tutorial instead: ESP8266 NodeMCU HTTPS Requests
Throughout this article, we’ll cover the following subjects:
To simplify, HTTPS is just the HTTP protocol but with encrypted data using SSL/TLS.
When using the ESP32 libraries to make HTTPS requests, they take care of encryption and decryption of the messages.
To make sure we are connected to the right server, we need to check the server certificate on the ESP32.
This means we need to download the server certificate and hard code it on our sketch so that we can check if we’re actually connected to the server we are expecting.
When a Certificate Authority issues a certificate, it signs the certificate with its root certificate.
This root certificate should be on the database of trusted certificates called a
So, when you connect to a website using your browser, it checks if its certificate was signed by a root certificate that belongs to its root store.
New root certificates are added or deleted to the root store with each browser update.
When you’re using an ESP32, you need to upload the certificates that you trust to your board.
Usually, you’ll add only the certificate for the server you’ll want to connect to.
But, it’s also possible to upload a root store to your board to have more options, and don’t have to worry about searching for a specific website’s certificate.
Your browser checks this certificate chain until it finds the root certificate.
If that certificate is in the browser’s root store, then it considers the certificate to be valid.
In this case, the DigiCert Global Root CA is in the browser’s root store.
So, it will display the “secure” icon on the browser bar.
Then, click on
A new window will open the all the information about the website’s certificate.
Click on the Details tab, make sure you select the root certificate (that’s what we’re looking for in this example), then click on
Select a place on your computer to save the certificate.
Save it on the default format: Base64-encoded ASCII, single certificate (*.pem, .crt).
And that’s it.
You can double-click on the certificate to check it’s details, including the expiration date.
Open the certificate using Notepad or other similar software.
You should get something similar as shown below.
We need to convert this to Arduino multi-line string, so that we can use it in our sketch.
Basically, you need to add a “ at the beginning of each line and a \n” \ at the end of each line, except the last line that you should add \n”.
So, you’ll get something as shown below:
If you scroll to the right, you’ll get the result of how secure the connection is.
You should get a “Probably Okay”.
If you scroll to the right, you’ll get the result of how secure the connection is.
You should get a “Probably Okay”.
Your connection is still encrypted, but it will skip SSL verification.
In this tutorial, we’ll cover the following concepts:
We’ll program the ESP32 using Arduino IDE, so before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE.
Follow the next tutorial to install the ESP32 on the Arduino IDE, if you haven’t already.
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux instructions)
We have several tutorials with the ESP32 interfacing with I2C devices:
0.96 inch I2C OLED display with ESP32
ESP32 Built-in OLED Board
I2C LCD Display with ESP32
BMP180 with ESP32
BME280 with ESP32
The SDA and SCL lines are active low, so they should be pulled up with resistors.
Typical values are 4.7k Ohm for 5V devices and 2.4k Ohm for 3.3V devices.
Most sensors we use in our projects are breakout boards that already have the resistors built-in.
So, usually, when you’re dealing with this type of electronics components you don’t need to worry about this.
Connecting an I2C device to an ESP32 is normally as simple as connecting GND to GND, SDA to SDA, SCL to SCL and a positive power supply to a peripheral, usually 3.3V (but it depends on the module you’re using).
| SDA (default is GPIO 21) | |
| SCL (default is GPIO 22) | |
| GND | |
| usually 3.3V or 5V |
So, the example sketch to read from the BME280 using other pins, for example GPIO 33 as SDA and and GPIO 32 as SCL is as follows.
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-i2c-communication-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define I2C_SDA 33
#define I2C_SCL 32
#define SEALEVELPRESSURE_HPA (1013.25)
TwoWire I2CBME = TwoWire(0);
Adafruit_BME280 bme;
unsigned long delayTime;
void setup() {
Serial.begin(115200);
Serial.println(F("BME280 test"));
I2CBME.begin(I2C_SDA, I2C_SCL, 100000);
bool status;
// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x76, &I2CBME);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
Serial.println("-- Default Test --");
delayTime = 1000;
Serial.println();
}
void loop() {
printValues();
delay(delayTime);
}
void printValues() {
Serial.print("Temperature = ");
Serial.print(bme.readTemperature());
Serial.println(" *C");
// Convert temperature to Fahrenheit
/*Serial.print("Temperature = ");
Serial.print(1.8 * bme.readTemperature() + 32);
Serial.println(" *F");*/
Serial.print("Pressure = ");
Serial.print(bme.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx.
Altitude = ");
Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(bme.readHumidity());
Serial.println(" %");
Serial.println();
}
View raw code
By placing the resistor on one side or the other, you can select different I2C addresses.
This also happens with other components.
We have a detailed tutorial explaining how to use an I2C multiplexer to connect multiple devices with the same address to the ESP32: Guide for TCA9548A I2C Multiplexer: ESP32, ESP8266, Arduino .
Each sensor is connected to a different I2C bus.
I2C Bus 1: uses GPIO 27 (SDA) and GPIO 26 (SCL);
I2C Bus 2: uses GPIO 33 (SDA) and GPIO 32 (SCL);
Want to learn more about I2C with the ESP32? Check this tutorial: ESP32 I2C Communication: Set Pins, Multiple Bus Interfaces and Peripherals (Arduino IDE) .
Wait a couple of seconds, and the I2C address of your peripheral will be printed in the Serial Monitor.
If you have more than one device connected to the same I2C bus, it will display the address of all devices.
Updated 14 May 2024
We have a similar tutorial for the ESP8266 NodeMCU board: Getting Started with InfluxDB
InfluxDB is an open-source high-performance time series database (TSDB) that can store large amounts of data per second.
Each data point you submit to the database is associated with a particular timestamp.
So, it is ideal for IoT datalogging projects like storing data from your weather station sensors.
You can run InfluxDB in InfluxDB Cloud , or locally on your laptop or Raspberry Pi .
“Why use InfluxDB Cloud? It’s a fast, elastic, serverless real-time monitoring platform, dashboarding engine, analytics service and event and metrics processor.” https://www.influxdata.com/products/influxdb-cloud/
The page that opens allows you to create buckets, and it also shows some sample code to interface the ESP8266 or ESP32 boards with InfluxDB.
On this page, you can generate a new API token if needed.
At this moment, you should have saved the following:
InfluxDB Server URL
InfluxDB Organization
InfluxDB Bucket Name
API Token
Now, go to your InfludDB account and go to the
Now, you can visualize your data.
Start by selecting the bucket you want—in our case, it’s the ESP32.
Then, we need to add filters to select our data.
Select the
Finally, click on the
Alternatively, you can also follow this project by wiring the circuit on a breadboard.
If you have another ESP32 model, you can still follow this project by assembling the circuit on a breadboard or modifying the PCB layout and wiring to match your ESP32 board.
The shield consists of:
BME280 temperature, humidity and pressure sensor;
LDR (light dependent resistor);
PIR motion sensor;
Status on-board LED;
Pushbutton;
3-pin socket that gives you access to GND, 5V and a GPIO where you can connect any output (like a relay module for example).
| BME280 | GPIO 21 (SDA), GPIO 22 (SCL) |
| PIR Motion Sensor | GPIO 27 |
| Light Dependent Resistor (LDR) | GPIO 33 |
| Pushbutton | GPIO 18 |
| LED | GPIO 19 |
| Additional Output | GPIO 32 |
Here’s the web server features to control the IoT shield:
To access the web server, you need to login with username and password (read: ESP32 Web Server HTTP Authentication: Username and Password Protected ).
After authenticating with the right credentials, you can access the web server.
There’s an icon at the top of the web page that you can click to logout.
Then, you’ll need to login again.
There are two toggle switches: one to control the output socket and another for the on-board status LED.
The status LED can also be controlled using the physical on-shield pushbutton.
The state of the LED automatically updates on the web page (like in this tutorial: Control Outputs with Web Server and a Physical Button Simultaneously ).
The toggle switch for the status LED can be useful to activate or deactivate something on the ESP32 and the LED gives you a visual feedback of what’s going on.
The temperature, humidity and luminosity are displayed on the web server and are automatically updated using server-sent events (SSE).
Finally, there’s a card that indicates if motion was detected.
After receiving the “Motion Detected” notification, you can click on the card to clear the warning.
These are the main features of the ESP32 IoT dashboard we’re going to build.
This combines many of the subjects approached in previous tutorials.
This is just an example on how you can control your shield.
The idea is to modify the code to add your own features to the project.
Having the parts assigned, place each component.
When you’re happy with the layout, make all the connections and route your PCB.
Save your project and export the Gerber files.
Turn your DIY breadboard circuits into professional PCBs – get 10 boards for approximately $5 + shipping (which will vary depending on your country).
Once you have your Gerber files, you can order the PCB.
Follow the next steps to download the file.
1.
Download the Gerber files – click here to download the .zip file
2.
Go to PCBWay website and open the PCB Instant Quote page.
3.
PCBWay can grab all the PCB details and automatically fill them for you.
Use the “Quick-order PCB (Autofill parameters)”.
4.
Press the “+ Add Gerber file” button to upload the provided Gerber files.
And that’s it.
You can also use the OnlineGerberViewer to check if your PCB is looking as it should.
If you aren’t in a hurry, you can use the China Post shipping method to lower your cost significantly.
In our opinion, we think they overestimate the China Post shipping time.
You can increase your PCB order quantity and change the solder mask color.
I’ve ordered the Blue color.
Once you’re ready, you can order the PCBs by clicking “Save to Cart” and complete your order.
Everything comes well packed, and the PCBs are really high-quality.
The letters on the silkscreen are really well-printed and easy to read.
Additionally, the solder sticks easily to the pads.
Besides the PCBs, I also received some stickers, a ruler and a pen.
Overall, we’re really satisfied with the PCBWay service.
1x SMD LED (1206)
1x 330 Ohm SMD resistors (1206)
2x 10k Ohm SMD resistor (1206)
1x Pushbutton (0.55 mm)
1x BME280
1x Mini PIR motion sensor
1x Light dependent resistor
1x Screw terminal blocks
Female pin header socket (2.54 mm)
Here’s the soldering tools I’ve used:
TS80 mini portable soldering iron
Solder 60/40 0.5mm diameter
Soldering mat
Read our review about the TS80 Soldering Iron: TS80 Soldering Iron Review – Best Portable Soldering Iron .
Start by soldering the SMD components.
Then, solder the header pins.
And finally, solder the other components or use header pins if you don’t want to connect the components permanently.
Here’s how the ESP32 IoT Shield looks like after assembling all the parts.
It should connect perfectly to the ESP32 DEVKIT DOIT V1 board.
To use the BME280 library, you also need to install theAdafruit_Sensor library.
Follow the next steps to install the library in your Arduino IDE:
Go to
To install the ESPAsyncWebServer and the AsyncTCP libraries, click on the following links to download the .zip folder:
ESPAsyncWebServer
AsyncTCP
These libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation Libraries folder.
Alternatively, in your Arduino IDE, you can go to
Open your browser and type the ESP32 IP address.
The following page should load.
Insert the username and password to access the web server.
By default the username is admin and the password is admin.
You can change that on the code.
After inserting the right credentials, you have access to the dashboard functionalities.
There are two toggle switches: one to control the status LED and another to control the additional output.
You can control the status LED using the toggle switch and also the shield physical button.
The state is automatically updated on the web page.
There’s another toggle button to control an additional output like a relay module.
Finally, there’s a card indicating if motion was detected or not.
When motion is detected, it shows the “Motion Detected” message.
This message is also updated automatically using server-sent events.
Once, you’ve seen this notification, you can click the motion card.
It will clear the warning message and show “No motion” instead”.
This tutorial covers how to interface the k-type thermocouple with your ESP32 board, install the required library and use a simple sketch to display the sensor readings in the Serial Monitor.
In this tutorial, we’ll cover the following topics:
A thermocouple can be made of different metals.
The metals used will affect the voltage range, cost, and sensitivity.
There are standardized metal combinations that result in different thermocouple types: B, E, J, N, K, R, T, and S.
Our tutorial is about the k-type thermocouple.
A k-type thermocouple is made out of chrome and alumel conductors and has a general temperature range of 200 to 1260oC (328 to 2300oF).
The MAX6675 thermocouple comes with a temperature sensor to measure temperature at the reference junction (cold-compensation reference) and amplifies the tiny voltage at the reference junction so that we can read it using our microcontrollers.
The MAX6675 amplifier communicates with a microcontroller using SPI communication protocol and the data is output in a 12-bit resolution.
Usually, you can get a pack with a k-type thermocouple and the MAX6675 amplifier.
Here’s a list of the MAX6675 most relevant features.
For a more detailed description, please consult the MAX6675 datasheet .
Direct digital conversion of type -K thermocouple output
Cold-junction compensaiton
Simple SPI-compatible serial interface
Operating voltage range: 3.0 to 5.5V
Operating temperature range: 20 to 85oC
Resolves temperatures to 0.25oC, allows readings as high as 1024oC (1875oF).
| MISO | |
| CS | |
| CLK | |
| VCC (3.3V or 5V) | |
| GND |
You can also follow the next table.
| GND | GND |
| VCC | 3.3V |
| SCK | GPIO 5 |
| CS | GPIO 23 |
| SO | GPIO 19 |

Using
As you can see, you have the option to choose from LittleFS, SPIFFS, or FatFS and you can even have the option to erase flash if needed.
Congratulations! You’ve successfully installed the Filesystem uploader plugin for the ESP32 on the Arduino IDE.
Click on that option.
A window will pop up for you to choose the filesystem you want to use.
As you can see, you have the option to choose from LittleFS, SPIFFS, or FatFS and you can even have the option to erase flash if needed.
Congratulations! You’ve successfully installed the Filesystem uploader plugin for the ESP32 on the Arduino IDE.
Make sure the
In this tutorial, we’ll cover the following topics:
Strain gauge load cells are composed of a metal bar with attached strain gauges (under the white glue in the picture above).
A strain gauge is an electrical sensor that measures force or strain on an object.
The resistance of the strain gauges varies when an external force is applied to an object, which results in a deformation of the object’s shape (in this case, the metal bar).
The change of the resistance is proportional to the load applied, which allows us to calculate the weight of objects.
Usually, load cells have four strain gauges hooked up in a Wheatstone bridge (as shown below) that allow us to get accurate resistance measurements.
For a more detailed explanation of how strain gauges work, read this article .
The wires coming from the load cell usually have the following colors:
Red: VCC (E+)
Black: GND (E-)
White: Output – (A-)
Green: Output + (A+)
You need to solder header pins on the GND, DT, SCK, and VCC pins to connect to the ESP32.
I soldered the load cell wires directly to the E+, E-, A-, and A+ pins.
The load cell wires were very thin and fragile, be careful when soldering to not damage the wires.
For more information about the HX711 amplifier, you can consult the HX711 datasheet .
You should attach the plates to the load cell in a way that creates a strain between the opposite ends of the metal bar.
The bottom plate holds the load cell, and the upper plate is where you place the objects.
The following figure shows what my load cell with the acrylic plates looks like.
Load Cell with HX711 Amplifier
| Red (E+) | GND | ||
| Black (E-) | GPIO 16 | ||
| White (A-) | GPIO 4 | ||
| Green (A+) | 3.3V |
Now, if you go to your project folder and open the platformio.ini file, there should be a line to include the library as follows:
lib_deps = bogde/HX711@^0.7.5
Also add the following line to change the Serial Monitor speed to 115200:
monitor_speed = 115200
In our case, the reading is -141449.
The known weight is 300g, so our calibration factor will be: -141449/300 = -471.497.
calibration factor = -141449/300 = -471.497
Save your calibration factor because you’ll need it later.
Yours will be different than ours.
Because the output of the sensor is proportional to the force applied to the load cell, you can calibrate your scale using whatever unit makes sense for you.
I used grams, but you can use pounds, kilograms, or even pieces of cat food ( as in this Andreas Spiess video ).
I experimented with several objects and compared them against the value on my kitchen scale, and the results were the same.
So, I can say that my ESP32 scale is at least as accurate as my kitchen scale.
| VCC | 3.3V or 5V* |
| GND | GND |
| SDA | GPIO 21 |
| SCL | GPIO 22 |
Alternatively, if you don’t want to use the library you can add the debounce code yourself (which is not difficult).
For a debounce code example, in the Arduino IDE, you can go to File > Examples > Digital > Debounce.
Once again, the readings on my ESP32 digital scale correspond to the readings on my kitchen scale.
To follow this part you need the following components:
2x ESP32 DOIT DEVKIT V1 Board
2x LoRa Transceiver modules (RFM95)
RFM95 LoRa breakout board (optional)
Jumper wires
Breadboard or stripboard
Alternative:
2x TTGO LoRa32 SX1276 OLED
Instead of using an ESP32 and a separated LoRa transceiver module, there are ESP32 development boards with a LoRa chip and an OLED built-in, which makes wiring much simpler.
If you have one of those boards, you can follow: TTGO LoRa32 SX1276 OLED Board: Getting Started with Arduino IDE .
You can also use other compatible modules like Semtech SX1276/77/78/79 based boards including: RFM96W, RFM98W, etc…
Alternatively, there are ESP32 boards with LoRa and OLED display built-in like the ESP32 Heltec Wifi Module , or the TTGO LoRa32 board .
Before getting your LoRa transceiver module, make sure you check the correct frequency for your location.
You can visit the following web page to learn more about RF signals and regulations according to each country .
For example, in Portugal we can use a frequency between 863 and 870 MHz or we can use 433MHz.
For this project, we’ll be using an RFM95 that operates at 868 MHz.
There are a few options that you can use to access the transceiver pins.
You may solder some wires directly to the transceiver;
Break header pins and solder each one separately;
Or you can buy a breakout board that makes the pins breadboard friendly.
We’ve soldered a header to the module as shown in the figure below.
This way you can access the module’s pins with regular jumper wires, or even put some header pins to connect them directly to a stripboard or breadboard.
You can connect a “real” antenna, or you can make one yourself by using a conductive wire as shown in the figure below.
Some breakout boards come with a special connector to add a proper antenna.
The wire length depends on the frequency:
868 MHz: 86,3 mm (3.4 inch)
915 MHz: 81,9 mm (3.22 inch)
433 MHz: 173,1 mm (6.8 inch)
For our module we need to use a 86,3 mm wire soldered directly to the transceiver’s ANA pin.
Note that using a proper antenna will extend the communication range.
Here’s the connections between the RFM95 LoRa transceiver module and the ESP32:
ANA: Antenna
GND:
GND
DIO3: don’t connect
DIO4: don’t connect
3.3V:
3.3V
DIO0:
GPIO 2
DIO1: don’t connect
DIO2: don’t connect
GND: don’t connect
DIO5: don’t connect
RESET: GPIO 14
NSS: GPIO 5
SCK: GPIO 18
MOSI: GPIO 23
MISO: GPIO 19
GND: don’t connect
Congratulations! You’ve built a LoRa Sender and a LoRa Receiver using the ESP32.
In this example we’re just sending an hello message, but the idea is to replace that text with useful information.
With this project you’ll learn how to:
Send sensor readings via LoRa radio between two ESP32 boards;
Add LoRa and Wi-Fi capabilities simultaneously to your projects (LoRa + Web Server on the same ESP32 board);
Use the TTGO LoRa32 SX1276 OLED board or similar development boards for IoT projects.
The LoRa sender sends BME280 sensor readings via LoRa radio every 10 seconds;
The LoRa receiver gets the readings and displays them on a web server;
You can monitor the sensor readings by accessing the web server;
The LoRa sender and the Lora receiver can be several hundred meters apart depending on their location.
So, you can use this project to monitor sensor readings from your fields or greenhouses if they are a bit apart from your house;
The LoRa receiver is running an asynchronous web server and the web page files are saved on the ESP32 filesystem (SPIFFS) ;
The LoRa receiver also shows the date and time the last readings were received.
To get date and time, we use the Network Time Protocol with the ESP32 .
For this project, we’ll use the following components:
| VIN | 3.3 V |
| GND | GND |
| SCL | GPIO 13 |
| SDA | GPIO 21 |
Finally, press the upload button.
Open the Serial Monitor at a baud rate of 115200.
You should get something as shown below.
The OLED of your board should be displaying the latest sensor readings.
Your LoRa Sender is ready.
Now, let’s move on to the LoRa Receiver.
As you can see, it contains a background image and styles to make the web page more appealing.
There are several ways to display images on an ESP32 web server .
We’ll store the image on the ESP32 filesystem (SPIFFS).
We’ll also store the HTML file on SPIFFS.
After a few seconds, the files should be successfully uploaded to SPIFFS.
Open the Serial Monitor at a baud rate of 115200.
You should get the ESP32 IP address, and you should start receiving LoRa packets from the sender.
You should also get the IP address displayed on the OLED.
With these boards we were able to get a stable LoRa communication up to 180 meters (590 ft) in open field.
These means that we can have the sender and receiver 180 meters apart and we’re still able to get and check the readings on the web server.
Getting a stable communication at a distance of 180 meters with such low cost boards and without any further customization is really impressive.
However, in a previous project using an RFM95 SX1276 LoRa transceiver chip with an home made antenna, we got better results: more than 250 meters with many obstacles in between.
The communication range will really depend on your environment, the LoRa board you’re using and many other variables.
In this tutorial, we’ll cover the following topics:
This microSD card module is also compatible with other microcontrollers like the Arduino and the ESP8266 NodeMCU boards.
To learn how to use the microSD card module with the Arduino, you can follow the next tutorial:
Guide to SD Card Module with Arduino
| 3V3 | 3.3V |
| CS | GPIO 5 |
| MOSI | GPIO 23 |
| CLK | GPIO 18 |
| MISO | GPIO 19 |
| GND | GND |
For this tutorial, you need the following parts:
ESP32 development board (read: Best ESP32 development boards )
MicroSD Card Module
MicroSD Card
Jumper Wires
Breadboard
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
There are several examples in Arduino IDE that show how to handle files on the microSD card using the ESP32.
In the Arduino IDE, go to
| GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 | |
| GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
You can also take a look at the following tables:
| VIN | 3V3 |
| GND | GND |
| SCL | GPIO 22 |
| SDA | GPIO 21 |
| 3V3 | 3.3V |
| CS | GPIO 5 |
| MOSI | GPIO 23 |
| CLK | GPIO 18 |
| MISO | GPIO 19 |
| GND | GND |
Let the project run for a while to gather some readings.
Then, insert the microSD card on your computer, and you should have a file called data.txt with the sensor readings.
On your local network, open a web browser and type the ESP32 IP address.
You should get access to the following web page built with the files stored on the microSD card.
For a detailed explanation of this project, refer to the following tutorial:
ESP32 Web Server with Files from microSD Card
We have a similar guide for the ESP8266: ESP8266 NodeMCU with MPU-6050 Accelerometer, Gyroscope and Temperature Sensor (Arduino)
In this guide we’ll cover two examples:
The gyroscope measures rotational velocity (rad/s), this is the change of the angular position over time along the X, Y and Z axis (roll, pitch and yaw).
This allows us to determine the orientation of an object.
| VCC | Power the sensor (3.3V or 5V) |
| GND | Common GND |
| SCL | SCL pin for I2C communication (GPIO 22) |
| SDA | SDA pin for I2C communication (GPIO 21) |
| XDA | Used to interface other I2C sensors with the MPU-6050 |
| XCL | Used to interface other I2C sensors with the MPU-6050 |
| AD0 | Use this pin to change the I2C address |
| INT | Interrupt pin – can be used to indicate that new measurement data is available |
Then, search for “
Finally, search for “
After installing the libraries, restart your Arduino IDE.
If you’re using VS Code with PaltformIO, copy the following lines to the platformio.ini file.
lib_deps = adafruit/Adafruit MPU6050 @ ^2.0.3
adafruit/Adafruit Unified Sensor @ ^1.1.4
The Adafruit MPU6050 library provides an example that dipslays the MPU-6050 gyroscope and accelerometer readings on an OLED display.
Learn more about using the OLED display with the ESP32: ESP32 OLED Display with Arduino IDE
For this example, copy the following code or go to
Move the sensor and see the values changing.
You can watch the video demonstration:
To build the web server we’ll use theESPAsyncWebServer librarythat provides an easy way to build an asynchronous web server and handle Server-Sent Events.
To learn more about Server-Sent Events, read: ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically) .
The web server displays the gyroscope values of the X, Y an Z axis;
The gyroscope values are updated on the web server every 10 milliseconds;
It displays the accelerometer values (X, Y, Z).
These values are updated every 200 milliseconds;
The MPU-6050 sensor module also measures temperature, so we’ll also display the temperature value.
The temperature is updated every second (1000 milliseconds);
All the readings are updated using Server-Sent Events;
There is a 3D representation of the sensor.
The orientation of the 3D object changes accordingly to the sensor orientation.
The current position of the sensor is calculated using the gyroscope values;
The 3D object is created using a JavaScript library called three.js ;
There are four buttons to adjust the position of the 3D object:
RESET POSITION: sets angular position to zero on all axis;
X: sets the X angular position to zero;
Y: sets the Y angular position to zero;
Z: sets the Z angular position to zero;
the Arduino code that handles the web server;
HTML file: to define the content of the web page;
CSS file: to style the web page;
JavaScript file: to program the behavior of the web page (handle web server responses, events and creating the 3D object).
The HTML, CSS and JavaScript files will be uploaded to the ESP32 SPIFFS (filesystem).
To upload files to the ESP32 filesystem, we’ll use the SPIFFS Uploader Plugin .
If you’re using PlatformIO + VS Code, read this article to learn how to upload files to the ESP32 filesystem:
ESP32 with VS Code and PlatformIO: Upload Files to Filesystem (SPIFFS)
The gyroscope measures rotational velocity (rad/s) – this is the change of the angular position over time along the X, Y and Z axis (roll, pitch and yaw).
This allows us to determine the orientation of an object.
The accelerometer measures acceleration (rate of change of the velocity of an object).
It senses static foces like gravity (9.8m/s2) or dynamic forces like vibrations or movement.
The MPU-6050 measures acceleration over the X, Y an Z axis.
Ideally, in a static object the acceleration over the Z axis is equal to the gravitational force, and it should be zero on the X and Y axis.
Using the values from the accelerometer, it is possible to calculate the roll and pitch angles using trigonometry, but it is not possible to calculate the yaw.
We can combine the information from both sensors to get accurate information about the sensor orientation.
Learn more about the MPU-6050 sensor: ESP32 with MPU-6050 Accelerometer, Gyroscope and Temperature Sensor .
Then, search for “
Finally, search for “
If you’re using VS Code with PlatformIO, copy the following lines to the platformio.ini file to include all the necessary libraries.
lib_deps = adafruit/Adafruit MPU6050 @ ^2.0.3
adafruit/Adafruit Unified Sensor @ ^1.1.4
me-no-dev/ESP Async WebServer @ ^1.2.3
arduino-libraries/Arduino_JSON @ 0.1.0
Inside that folder you should save the HTML, CSS and JavaScript files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your networks credentials to the code.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
The ESP32 requests temperature readings from the BME280 sensor.
The temperature readings are published in the
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
You can use any other MQTT broker, including a cloud MQTT broker.
We’ll show you how to do that in the code later on.
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works .
To use the BME280 library, you also need to install the Adafruit Unified Sensor .
Follow the next steps to install the library in your Arduino IDE:
3.
Search for “
After installing the libraries, restart your Arduino IDE.
To learn more about the BME280 sensor, read our guide: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity) .
Click the MQTT node and edit its properties.
The Server field refers to the MQTT broker.
In our case, the MQTT broker is the Raspberry Pi, so it is set to localhost:1883.
If you’re using a Cloud MQTT broker, you should change that field.
Insert the topic you want to be subscribed to and the QoS.
This previous MQTT node is subscribed to the
Wire your nodes as shown below:
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
That’s it! You have your ESP32 board publishing BME280 temperature, humidity and pressure readings to Node-RED via MQTT.
The ESP32 requests sensor readings from the BME680 sensor.
The temperature readings are published in the
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
You can use any other MQTT broker, including a cloud MQTT broker.
We’ll show you how to do that in the code later on.
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works .
To use the BME680 library, you also need to install the Adafruit Unified Sensor.
Follow the next steps to install the library in your Arduino IDE:
3.
Search for “
After installing the libraries, restart your Arduino IDE.
To learn more about the BME680 sensor, read our guide: ESP32 with BME680 Sensor using Arduino IDE (Pressure, Temperature, Humidity) .
For this tutorial you need the following parts:
ESP32 (read Best ESP32 development boards )
BME680 – BME680 with ESP32 Guide
Raspberry Pi board (readBest Raspberry Pi Starter Kits )
MicroSD Card – 16GB Class10
Raspberry Pi Power Supply (5V 2.5A)
Jumper wires
Breadboard
Click the MQTT node and edit its properties.
The Server field refers to the MQTT broker.
In our case, the MQTT broker is the Raspberry Pi, so it is set to localhost:1883.
If you’re using a Cloud MQTT broker, you should change that field.
Insert the topic you want to be subscribed to and the QoS.
This previous MQTT node is subscribed to the
Wire your nodes as shown below:
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
That’s it! You have your ESP32 board publishing BME680 temperature, humidity, pressure and gas resistance readings to Node-RED via MQTT.
The ESP32 requests temperature and humidity readings from the DHT11 or DHT22 sensor;
Temperature readings are published in the
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
You can use any other MQTT broker, including a cloud MQTT broker.
We’ll show you how to do that in the code later on.
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works .
3.
After installing the DHT library from Adafruit, type “
After installing the libraries, restart your Arduino IDE.
To learn more about the DHT11 or DHT22 temperature sensor, read our guide: ESP32 with DHT11/DHT22 Temperature and Humidity Sensor using Arduino IDE
Click the MQTT node and edit its properties.
The Server field refers to the MQTT broker.
In our case, the MQTT broker is the Raspberry Pi, so it is set to localhost:1883.
If you’re using a Cloud MQTT broker, you should change that field.
Insert the topic you want to be subscribed to and the QoS.
This previous MQTT node is subscribed to the
Wire your nodes as shown below:
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
That’s it! You have your ESP32 board publishing DHT temperature and humidity readings to Node-RED via MQTT.
The ESP32 request temperature readings from the DS18B20 sensor.
The readings are published in the
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
You can use any other MQTT broker, including a cloud MQTT broker.
We’ll show you how to do that in the code later on.
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works .
3.
Then, search for “
After installing the libraries, restart your Arduino IDE.
To learn more about the DS18B20 temperature sensor, read our guide: ESP32 DS18B20 Temperature Sensor with Arduino IDE (Single, Multiple, Web Server) .
Click the MQTT node and edit its properties as follows:
The Server field refers to the MQTT broker.
In our case, the MQTT broker is the Raspberry Pi, so it is set to localhost:1883.
If you’re using a Cloud MQTT broker, you should change that field.
Insert the topic you want to be subscribed to and the QoS.
Set the following properties for the gauge node.
Edit the chart node as follows:
Wire your nodes as shown below:
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
That’s it! You have your ESP32 board publishing sensor readings to Node-RED via MQTT.
The Node-RED application publishes messages (“
Raspberry Pi – read Best Raspberry Pi 3 Starter Kits
ESP32 DOIT DEVKIT V1 Board – read ESP32 Development Boards Review and Comparison
BME280 sensor module
1x 5mm LED
1x 220 Ohm resistor
Breadboard
Jumper wires
The sensor can communicate using either SPI or I2C communication protocols (there are modules of this sensor that just communicate with I2C, these just come with four pins).
To use SPI communication protocol, use the following pins:
SCK – this is the SPI Clock pin
SDO – MISO
SDI – MOSI
CS – Chip Select
To use I2C communication protocol, the sensor uses the following pins:
SCK –SCL pin
SDI – SDA pin
Here’s how your circuit should look:
Next, in the Node-RED window, at the top right corner, select the menu, and go to
Then, paste the code provided and click
The following nodes should load:
After making any changes, click the
Note: there’s also a waterproof version of the DS18B20 temperature sensor .
Here’s the main specifications of the DS18B20 temperature sensor:
Comunicates over 1-wire bus communication
Operating range temperature: -55oC to 125oC
Accuracy +/-0.5 oC (between the range -10oC to 85oC)
From left to right: the first pin is GND, the second is data, and the rightmost pin is VCC.
ESP32 DOIT DEVKIT V1 Board – read ESP32 Development Boards Review and Comparison
DS18B20 temperature sensor (we’re using 3 sensors in this example)
4.7k Ohm resistor
Jumper wires
Breadboard
When wiring the DS18B20 temperature sensor you need to add a 4.7k Ohm resistor between VCC and the data line.
The following schematic shows an example for three sensors (you can add more sensors if needed).
In the previous schematic, the round side of the sensor is facing backwards.
The flat part is facing forward.
Untick the “
The example code below reads temperature in Celsius and Fahrenheit from each sensor and prints the results in the Serial Monitor.
/*
* Rui Santos
* Complete Project Details https://randomnerdtutorials.com
*/
// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is connected to GPIO15
#define ONE_WIRE_BUS 15
// Setup a oneWire instance to communicate with a OneWire device
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
DeviceAddress sensor1 = { 0x28, 0xFF, 0x77, 0x62, 0x40, 0x17, 0x4, 0x31 };
DeviceAddress sensor2 = { 0x28, 0xFF, 0xB4, 0x6, 0x33, 0x17, 0x3, 0x4B };
DeviceAddress sensor3= { 0x28, 0xFF, 0xA0, 0x11, 0x33, 0x17, 0x3, 0x96 };
void setup(void){
Serial.begin(115200);
sensors.begin();
}
void loop(void){
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
Serial.print("Sensor 1(*C): ");
Serial.print(sensors.getTempC(sensor1));
Serial.print(" Sensor 1(*F): ");
Serial.println(sensors.getTempF(sensor1));
Serial.print("Sensor 2(*C): ");
Serial.print(sensors.getTempC(sensor2));
Serial.print(" Sensor 2(*F): ");
Serial.println(sensors.getTempF(sensor2));
Serial.print("Sensor 3(*C): ");
Serial.print(sensors.getTempC(sensor3));
Serial.print(" Sensor 3(*F): ");
Serial.println(sensors.getTempF(sensor3));
delay(2000);
}
View raw code
Open the Serial Monitor at a baud rate of 115200 and you should get something similar.
After that, it will change to the other timezone you’ve set on the code.
In our case, we set to Berlin.
After that, you should see the change to winter time.
In our case, when it’s 2 a.m., the clock goes back one hour.
We also check if it adjusts to summer time when it comes the time.
In the example below, you can see that the clock goes forward one hour to set summer time.
By the end of this tutorial, you’ll be able to easily add OTA capabilities to your web server projects with the ESP32 to upload new firmware and files to the filesystem wirelessly in the future.
We have a similar tutorial for the ESP8266 NodeMCU board: ESP8266 NodeMCU OTA (Over-the-Air) Updates – AsyncElegantOTA using Arduino IDE
The only disadvantage of OTA programming is that you need to add the code for OTA in every sketch you upload so that you’re able to use OTA in the future.
In the case of the AsyncElegantOTA library, it consists of just three lines of code.
It is compatible with the ESPAsyncWebServer library;
You just need to add three lines of code to add OTA capabilities to your “regular” Async Web Server;
It allows you to update not only new firmware to the board but also files to the ESP32 filesystem (SPIFFS);
It provides a beautiful and modern web server interface;
It works extremely well.
If you like this library and you’ll use it in your projects, consider supporting the developer’s work .
In your local network, open your browser and type the ESP32 IP address.
You should get access the root (/) web page with some text displayed.
Now, imagine that you want to modify your web server code.
To do that via OTA, go to the ESP IP address followed by /update.
The following web page should load.
Follow the next sections to learn how to upload new firmware using AsyncElegantOTA.
4.
Now, you need to upload that file using the ElegantOTA page.
Go to your ESP IP address followed by /update.
Make sure you have the
5.
When it’s finished, click on the
6.
Then, you can go to the root (/) URL to access the new web server.
This is the page you should see when you access the ESP IP address on the root (/) URL.
You can click on the button to turn the ESP32 on-board LED on and off.
Because we’ve also added OTA capabilities to this new web server, we can upload a new sketch in the future if needed.
You just need to go to the ESP32 IP address followed by /update.
Congratulations, you’ve uploaded new code to your ESP32 via Wi-Fi using AsyncElegantOTA.
Continue reading if you want to learn how to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.
Copy the following code to your Arduino IDE.
/*
Rui Santos
Complete project details
- Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/
- VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
// Import required libraries
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <AsyncElegantOTA.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create a WebSocket object
AsyncWebSocket ws("/ws");
// Set number of outputs
#define NUM_OUTPUTS 4
// Assign each GPIO to an output
int outputGPIOs[NUM_OUTPUTS] = {2, 4, 12, 14};
// Initialize SPIFFS
void initSPIFFS() {
if (!SPIFFS.begin(true)) {
Serial.println("An error has occurred while mounting SPIFFS");
}
Serial.println("SPIFFS mounted successfully");
}
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
String getOutputStates(){
JSONVar myArray;
for (int i =0; i<NUM_OUTPUTS; i++){
myArray["gpios"][i]["output"] = String(outputGPIOs[i]);
myArray["gpios"][i]["state"] = String(digitalRead(outputGPIOs[i]));
}
String jsonString = JSON.stringify(myArray);
return jsonString;
}
void notifyClients(String state) {
ws.textAll(state);
}
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
if (strcmp((char*)data, "states") == 0) {
notifyClients(getOutputStates());
}
else{
int gpio = atoi((char*)data);
digitalWrite(gpio, !digitalRead(gpio));
notifyClients(getOutputStates());
}
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,AwsEventType type,
void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
void initWebSocket() {
ws.onEvent(onEvent);
server.addHandler(&ws);
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
// Set GPIOs as outputs
for (int i =0; i<NUM_OUTPUTS; i++){
pinMode(outputGPIOs[i], OUTPUT);
}
initSPIFFS();
initWiFi();
initWebSocket();
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html", "text/html",false);
});
server.serveStatic("/", SPIFFS, "/");
// Start ElegantOTA
AsyncElegantOTA.begin(&server);
// Start server
server.begin();
}
void loop() {
ws.cleanupClients();
}
View raw code
Insert your network credentials in the following variables and save the code.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
After this, with the ESP32 disconnected from your computer (that’s the whole purpose of OTA), click on
You’ll get an error because there isn’t any ESP32 board connected to your computer – don’t worry.
Scroll up on the debugging window until you find the .spiffs.bin file location.
That’s that file that you should upload (in our case the file is called Web_Server_OTA_ESP32_Example_2.spiffs.bin.
And this is the path where our file is located:
C:\Users\sarin\AppData\Local\Temp\arduino_build_675367\Web_server_OTA_ESP32_Example_2.spiffs.bin
To access that file on my computer, I need to make hidden files visible (the AppData folder was not visible).
Check if that’s also your case.
Once you reach the folder path, you want to get the file with .spiffs.bin extension.
To make things easier you can copy that file to your project folder.
Now that we have a .bin file from the data folder, we can upload that file.
Go to your ESP32 IP address followed by /update.
Make sure you have the
Then, select the file with the .spiffs.bin extension.
After successfully uploading, click the
To see the web server working, you can connect 4 LEDs to your ESP32 on GPIOS: 2, 4, 12, and 14.
You should be able to control those outputs from the web server.
If you need to update something on your project, you just need to go to your ESP32 IP address followed by /update.
Congratulations! You’ve successfully uploaded files to the ESP32 filesystem using AsyncElegantOTA.
By the end of this tutorial, you’ll be able to easily add OTA capabilities to your web server projects with the ESP32 to upload new firmware and files to the filesystem wirelessly in the future.
Recommended reading: Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266
We have a similar tutorial for the ESP8266 NodeMCU board: ESP8266 NodeMCU OTA (Over-the-Air) Updates – AsyncElegantOTA (VS Code + PlatformIO)
The only disadvantage of OTA programming is that you need to add the code for OTA in every sketch you upload so that you’re able to use OTA in the future.
In the case of the AsyncElegantOTA library, it consists of just three lines of code.
It is compatible with the ESPAsyncWebServer library;
You just need to add three lines of code to add OTA capabilities to your “regular” Async Web Server;
It allows you to update not only new firmware to the board, but also files to the ESP32 filesystem (SPIFFS);
It provides a beautiful and modern web server interface;
It works extremely well.
If you like this library and you’ll use it in your projects, consider supporting the developer’s work .
In your local network, open your browser and type the ESP32 IP address.
You should get access the root (/) web page with some text displayed.
Now, imagine that you want to modify your web server code.
To do that via OTA, go to the ESP IP address followed by /update.
The following web page should load.
Follow the next sections to learn how to upload new firmware using the AsyncElegantOTA.
You can click on the button to turn the ESP32 on-board LED on and off.
Because we’ve also added OTA capabilities to this new web server, we can upload a new sketch in the future if needed.
You just need to go to the ESP32 IP address followed by /update.
Congratulations, you’ve uploaded new code to your ESP32 via Wi-Fi using ElegantOTA.
Continue reading if you want to learn how to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.
Go to the ESP IP address followed by /update and upload the new firmware as shown previously.
Next, we’ll see how to upload the files to the filesystem.
After building the filesystem image, you should have a spiffs.bin file in the following path (or similar):
.pio/build/esp32doit-devkit-v1/
That’s that file that you should upload to update the filesystem.
Go to your ESP IP address followed by/update.
Make sure you have the
After successfully uploading, click the
To see the web server working, you can connect 4 LEDs to your ESP32 on GPIOS: 2, 4, 12 and 14.
You should be able to control those outputs from the web server.
If you need to update something on your project, you just need to go to your ESP32 IP address followed by /update.
Congratulations! You’ve successfully uploaded files to the ESP32 filesystem using ElegantOTA.
Now, you can upload code to your ESP32 over-the-air using a browser on your local network.
To test the OTA Web Updater you can disconnect the ESP32 from your computer and power it using a power bank, for example (this is optional, we’re suggesting this to mimic a situation in which the ESP32 is not connected to your computer).
Enter the username and the password:
A new file on the folder sketch should be created.
Go to
The ESP32 built-in LED should be blinking.
Congratulations! You’ve uploaded a new code to your ESP32 over-the-air.
Additionally, there are pins with specific features that make them suitable or not for a particular project.
The following table shows what pins are best to use as inputs, outputs and which ones you need to be cautious.
The pins highlighted in green are OK to use.
The ones highlighted in yellow are OK to use, but you need to pay attention because they may have an unexpected behavior mainly at boot.
The pins highlighted in red are not recommended to use as inputs or outputs.
| pulled up | OK | outputs PWM signal at boot, must be LOW to enter flashing mode | |
| TX pin | OK | debug output at boot | |
| OK | OK | connected to on-board LED, must be left floating or LOW to enter flashing mode | |
| OK | RX pin | HIGH at boot | |
| OK | OK | ||
| OK | OK | outputs PWM signal at boot, strapping pin | |
| x | x | connected to the integrated SPI flash | |
| x | x | connected to the integrated SPI flash | |
| x | x | connected to the integrated SPI flash | |
| x | x | connected to the integrated SPI flash | |
| x | x | connected to the integrated SPI flash | |
| x | x | connected to the integrated SPI flash | |
| OK | OK | boot fails if pulled high, strapping pin | |
| OK | OK | ||
| OK | OK | outputs PWM signal at boot | |
| OK | OK | outputs PWM signal at boot, strapping pin | |
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | OK | ||
| OK | input only | ||
| OK | input only | ||
| OK | input only | ||
| OK | input only |

| GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 | |
| GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
Move your hand in front of the PIR sensor.
The LED should turn on, and a message is printed in the Serial Monitor saying “MOTION DETECTED!!!”.
After 10 seconds the LED should turn off.
We have a similar tutorial for the ESP8266 NodeMCU board:
ESP8266 NodeMCU Plot Sensor Readings in Charts (Multiple Series)
Each sensor has a unique 64-bit serial number, which means you can connect multiple sensors to the same GPIO—as we’ll do in this tutorial.
Learn more about the DS18B20 temperature sensor:
ESP32 DS18B20 Temperature Sensor with Arduino IDE (Single, Multiple, Web Server)
ESP32 with Multiple DS18B20 Temperature Sensors
To learn more about SSE, you can read:
ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Untick the “
You should save the HTML, CSS, and JavaScript files inside a folder called
Inside that folder you should save the HTML, CSS and JavaScript files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your networks credentials and the sensors’ addresses to the code.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
You can select a point to see its value and timestamp.
New to the ESP32? Start here: Getting Started with the ESP32 Development Board .
Pushover is a mobile and desktop app compatible with Android and iOS and Windows, MacOS, and Linux.
It allows you to receive notifications from different sources and services and integrates with many applications.
You can receive notifications on all your devices simultaneously or send them to groups with multiple users.
Additionally, you can customize things such as priority levels, set silent hours, and even different sounds depending on the type of notification.
After publishing this previous tutorial , we found that many of our readers were already using Pushover for other types of notifications.
So, we thought it would be useful to know how to integrate Pushover with the ESP32 so that you have all your notifications in one place.
After creating your account, you’ll have a free 30-day trial period.
After that, you’ll need to go to your email to verify your account.
At the top right corner, there’s the
Give a name and description(optional) to the API Token.
You can also add an icon to that.
We added an icon of an ESP32.
So, when we receive a notification, it will be accompanied by the ESP32 icon.
Finally, create the application.
Now, the application will show up on your dashboard under the Your Applications section.
Click on the application name to get its API token.
On that menu, you can also check how many notifications you have sent with that API token.
Save the API token because you’ll need it later.
Now that you have the user key and API token, you can start sending ESP32 notifications with Pushover.
And you should receive the notification on your smartphone.
You can click on the message to open it.
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
All GPIOs are outputting the same PWM signal.
So, all three LEDs increase and decrease the brightness simultaneously, resulting in a synchronized effect.
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU with RCWL-0516 Microwave Radar Proximity Sensor (Arduino IDE) .
Throughout this tutorial, we’ll cover the following contents:
The RCWL-0516 is a small, inexpensive sensor that uses microwave radar to detect the presence of moving objects.
The sensor works by emitting a beam of microwaves and then detecting the Doppler shift in the reflected waves as objects move past.
Usually, these sensors are sold as a pack of five and don’t come with header pins.
So, you may need to get header pins separately and then solder them yourself.
Note: even though it mentions a detection range of up to 7 meters, I couldn’t get those results with my setup.
However, I got very good feedback from some of our readers about this sensor.
Here’s a summary of some of the key features of the RCWL-0516 sensor:
Uses microwave radar to detect moving objects
Detection range of up to 7 meters
Can detect objects moving at speeds of up to 2 meters per second
Built-in adjustable delay time
Low power consumption
Inexpensive
When the output of the LDR is bigger than 0.7V, the OUT pin will output a HIGH signal when motion is detected.
If motion is detected but the output of the LDR is smaller than 0.7V, the output will be LOW.
This means that when attaching an LDR, the sensor will only sense motion when it’s dark.
You can adjust the sensitivity of the LDR, by connecting a resistor on the R-CDS pads (see the following section), or by adding a pull-up resistor externally in parallel with the CDS pin.
In my case, I added a pull-up 22KOhm resistor to the LDR pin so that it could detect motion when there is low light.
Without the resistor, not even in very dark conditions I had a positive output.
You might need to try with different resistance values to see which one works best for your scenario.
At the back of the sensor, there are three pads for additional SMD components (0805 dimensions):
The following information was taken from this GitHub page .
| 3.3V power output (not to power the sensor) | |
| ground pin | |
| output pin (goes HIGH when motion is detected) | |
| input voltage to power the sensor (4V to 28V) | |
| light-dependent resistor output |
The microwave radar proximity sensor is many times used as an alternative to the PIR motion sensor, depending on the project application.
The following table compares both sensors:
| RCWL-0516 Microwave Radar | PIR Motion Sensor | |
| Active Sensor (emits microwave signals and detects reflections). | Passive Sensor (detects infrared radiation emitted by objects). | |
| Longer range, typically up to 7+ meters. | Shorter range, typically a few meters, depending on the model. | |
| Can sense through non-metallic materials. | Obstructed by certain materials (e.g., glass) | |
| Highly sensitive, may give false positives. | Not so sensitive, may miss subtle movements. Only detects living things that emit heat. | |
| Broad coverage with wide radar pattern. | Narrow field of view. |
| 3V3 | don’t connect |
| GND | GND |
| OUT | GPIO15 (or any other GPIO of your choice) |
| VIN | VIN (or a voltage between 4 and 28V) |
| CDS | don’t connect |
Wave your hand in front of the motion sensor.
You should get a “Motion detected” message followed by a “Motion stopped” message after two seconds.
Additionally, the on-board LED will light up when motion is detected.
If you have an LDR attached, you’ll need to decrease the luminosity to get positive results.
Learn how to control a relay module with ESP8266 board:
There are relay modules whose electromagnet can be powered by 5V and with 3.3V.
Both can be used with the ESP32 – you can either use the VIN pin (that provides 5V) or the 3.3V pin.
Additionally, some come with built-in optocoupler that add an extra “layer” of protection, optically isolating the ESP32 from the relay circuit.
On the left side, there are two sets of three sockets to connect high voltages, and the pins on the right side (low-voltage) connect to the ESP32 GPIOs.
The relay module shown in the previous photo has two connectors, each with three sockets: common (COM), Normally Closed (NC), and Normally Open (NO).
The low-voltage side has a set of four pins and a set of three pins.
The first set consists of VCC and GND to power up the module, and input 1 (IN1) and input 2 (IN2) to control the bottom and top relays, respectively.
If your relay module only has one channel, you’ll have just one IN pin.
If you have four channels, you’ll have four IN pins, and so on.
The signal you send to the IN pins, determines whether the relay is active or not.
The relay is triggered when the input goes below about 2V.
This means that you’ll have the following scenarios:
The second set of pins consists of GND, VCC, and JD-VCC pins.
The JD-VCC pin powers the electromagnet of the relay.
Notice that the module has a jumper cap connecting the VCC and JD-VCC pins; the one shown here is yellow, but yours may be a different color.
With the jumper cap on, the VCC and JD-VCC pins are connected.
That means the relay electromagnet is directly powered from the ESP32 power pin, so the relay module and the ESP32 circuits are not physically isolated from each other.
Without the jumper cap, you need to provide an independent power source to power up the relay’s electromagnet through the JD-VCC pin.
That configuration physically isolates the relays from the ESP32 with the module’s built-in optocoupler, which prevents damage to the ESP32 in case of electrical spikes.
In this example, we’re controlling a lamp.
We just want to light up the lamp occasionally, so it is better to use a normally open configuration.
We’re connecting the IN1 pin to GPIO 26, you can use any other suitable GPIO.
See ESP32 GPIO Reference Guide .
The following code will light up your lamp for 10 seconds and turn it off for another 10 seconds.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-relay-module-ac-web-server/
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
const int relay = 26;
void setup() {
Serial.begin(115200);
pinMode(relay, OUTPUT);
}
void loop() {
// Normally Open configuration, send LOW signal to let current flow
// (if you're usong Normally Closed configuration send HIGH signal)
digitalWrite(relay, LOW);
Serial.println("Current Flowing");
delay(5000);
// Normally Open configuration, send HIGH signal stop current flow
// (if you're usong Normally Closed configuration send LOW signal)
digitalWrite(relay, HIGH);
Serial.println("Current not Flowing");
delay(5000);
}
View raw code
In this section, we’ve created a web server example that allows you to control as many relays as you want via web server whether they are configured as normally opened or as normally closed.
You just need to change a few lines of code to define the number of relays you want to control and the pin assignment.
To build this web server, we use the ESPAsyncWebServer library .
Now, you can use the buttons to control your relays remotely using your smartphone.

In this tutorial, we’ll cover the following topics:
;
;
;
;
;
| putChar(const char* key, int8_t value) | |
| putUChar(const char* key, int8_t value) | |
| putShort(const char* key, int16_t value) | |
| putUShort(const char* key, uint16_t value) | |
| putInt(const char* key, int32_t value) | |
| putUInt(const char* key, uint32_t value) | |
| putLong(const char* key, int32_t value) | |
| putULong(const char* key, uint32_t value) | |
| putLong64(const char* key, int64_t value) | |
| putULong64(const char* key, uint64_t value) | |
| putFloat(const char* key, const float_t value) | |
| putDouble(const char* key, const double_t value) | |
| putBool(const char* key, const bool value) | |
| putString(const char* key, const String value) | |
| putBytes(const char* key, const void* value, size_t len) |
| getChar(const char* key, const int8_t defaultValue) | |
| getUChar(const char* key, const uint8_t defaultValue) | |
| getShort(const char* key, const int16_t defaultValue | |
| getUShort(const char* key, const uint16_t defaultValue) | |
| getInt(const char* key, const int32_t defaultValue) | |
| getUInt(const char* key, const uint32_t defaultValue) | |
| getLong(const char* key, const int32_t defaultValue) | |
| getULong(const char* key, const uint32_t defaultValue) | |
| getLong64(const char* key, const int64_t defaultValue) | |
| gettULong64(const char* key, const uint64_t defaultValue) | |
| getFloat(const char* key, const float_t defaultValue) | |
| getDouble(const char* key, const double_t defaultValue) | |
| getBool(const char* key, const bool defaultValue) | |
| getString(const char* key, const String defaultValue) | |
| getString(const char* key, char* value, const size_t maxLen) | |
| getBytes(const char* key, void * buf, size_t maxLen) |
In the following example, we’ll show you how to read the network credentials from preferences and use them to connect the ESP32 to your network.
You don’t want this to happen.
You want the ESP32 to remember what was happening before losing power and return to the last state.
To solve this problem, you can save the lamp’s state in the flash memory.
Then, you need to add a condition at the beginning of your sketch to check the last lamp state and turn the lamp on or off accordingly.
The following figure shows what we’re going to do:
We’ll show you an example using an LED and a pushbutton.
The pushbutton controls the LED state.
The LED keeps its state between resets.
This means that if the LED is lit when you remove power, it will be lit when it gets powered again.
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
When the ESP32 restarts, it will read the last state saved on Preferences and set the LED to that state.
It also prints a message on the Serial Monitor whenever there’s a change on the GPIO state.
Updated 24 June 2023
In this tutorial, we cover the following topics:
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino)
In the Select app field, choose
Now, you should have an app password that you’ll use on the ESP32 code to send the emails.
If you’re using another email provider, check how to create an app password.
You should be able to find the instructions with a quick google search “
Check your email account.
You should have received an email from your ESP32 board.
If you set the option to send a message with HTML text, this is what the message looks like:
If you’ve enabled the raw text message, this is the email that you should receive.
Your folder structure should look as follows (
After moving the files to the
Then, select
You should get a success message on the debugging window.
If the files were successfully uploaded, move on to the next section.
Check the recipient’s email address.
You should have a new email with two attachments.
We have a similar tutorial for the ESP8266 board:
ESP8266 NodeMCU: Send Messages to WhatsApp
“WhatsApp Messenger, or simply WhatsApp, is an internationally available American freeware, cross-platform centralized instant messaging and voice-over-IP service owned by Meta Platforms.” It allows you to send messages using your phone’s internet connection, so you can avoid SMS fees.
WhatsApp is free and is available for Android and iOS.
Install WhatsApp on your smartphone if you don’t have it already.
Go to your WhatsApp account.
After a few seconds, you should receive the ESP32 message.
Updated 24 January, 2024
| Power | Red |
| GND | Black, or brown |
| Signal | Yellow, orange, or white |
But if you’re using more than one servo or a different model, you’ll probably need to power up your servos using an external power supply.
If you’re using a small servo like the S0009, you need to connect:
GND -> ESP32 GND pin;
Power -> ESP32 VIN pin;
Signal -> GPIO 13 (or any PWM pin).
(This schematic uses the ESP32 DEVKIT V1 module version with 36 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
To control the motor you can simply use the PWM capabilities of the ESP32 by sending a 50Hz signal with the appropriate pulse width.
Or you can use a library to make this task much simpler.
Open your browser, paste the ESP IP address, and you should see the web page you created previously.
Move the slider to control the servo motor.
In the Serial Monitor, you can also see the HTTP requests you’re sending to the ESP32 when you move the slider.
Experiment with your web server for a while to see if it’s working properly.
There is a method provided by the WiFi.h library that allows you to set a custom hostname.
First, start by defining your new hostname.
For example:
String hostname = "ESP32 Node Temperature";
Then, call the WiFi.setHostname() function before calling WiFi.begin().
You also need to call WiFi.config() as shown below:
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setHostname(hostname.c_str()); //define hostname
You can copy the complete example below:
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-set-custom-hostname-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
// Replace with your network credentials (STATION)
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
String hostname = "ESP32 Node Temperature";
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setHostname(hostname.c_str()); //define hostname
//wifi_station_set_hostname( hostname.c_str() );
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
Serial.print("RRSI: ");
Serial.println(WiFi.RSSI());
}
void loop() {
// put your main code here, to run repeatedly:
}
View raw code
You can use this previous snippet of code in your projects to set a custom hostname for the ESP32.
Besides Wi-Fi and Bluetooth, you can communicate with this ESP32 board using SMS or phone calls and you can connect it to the internet using your SIM card data plan.
This is great for IoT projects that don’t have access to a nearby router.
The package includes some header pins, a battery connector, and an external antenna that you should connect to your board.
However, we had some issues with that antenna, so we decided to switch to another type of antenna and all the problems were solved.
The following figure shows the new antenna.
In a previous project , we’ve created our own server domain with a database to plot sensor readings in charts that you can access from anywhere in the world.
In this project, we’ll publish sensor readings to that server.
You can publish your sensor readings to any other service, like ThingSpeak, IFTTT, etc…
If you want to follow this exact project, you should follow that previous tutorial first to prepare your own server domain.
Then, upload the code provided in this project to your ESP32 board.
In summary, here’s how the project works:
The T-Call ESP32 SIM800L board is in deep sleep mode.
It wakes up and connects to the internet using your SIM card data plan.
It publishes the sensor readings to the server and goes back to sleep.
In our example, the sleep time is 60 minutes, but you can easily change it in the code.
We’ll be using a BME280 senso r, but you should be able to use any other sensor that best suits your needs.
After installing the libraries, restart your Arduino IDE.
We’re connecting the SDA pin to GPIO 18 and the SCL pin to GPIO 19.
We’re not using the default I2C GPIOs because they are being used by the battery power management IC of the T-Call ESP32 SIM800L board.
In this example, it publishes new sensor readings every 60 minutes, but for testing purposes you can use a shorter delay.
Then, open a browser and type your server domain on the
In this example, we’ll use a DS18B20 temperature sensor , and we’ll send a text message when the temperature is above 28oC.
Once the temperature has decreased below the threshold, we’ll send another SMS alert.
To send an SMS with the T-Call ESP32 SIM800L module, you just need to use modem.sendSMS(SMS_TARGET, smsMessage) after initializing a modem object for the SIM800L module (using the TinyGSM library).
The ESP32 gets new temperature readings every 5 seconds
It checks if the temperature is above the threshold value
If it’s above the threshold value, it sends an alert SMS with the current temperature value
When the temperature goes below the threshold, it sends another alert
The ESP32 sends only one SMS every time the temperature readings cross the threshold value
You can modify this project for your specific case.
For example, you may want to put the ESP32 in deep sleep mode and send an SMS every hour with the current temperature readings, etc.
Besides Wi-Fi and Bluetooth, you can communicate with this ESP32 board using SMS, phone calls or you can connect it to the internet.
In this tutorial, you’ll learn how to send an SMS notification.
For a complete overview of this board, you can read the following article: $11 TTGO T-Call ESP32 with SIM800L GSM/GPRS (Overview)
Then, search for “
After installing the libraries, restart your Arduino IDE.
To follow this tutorial you need the following parts:
After a few seconds, you should receive an SMS on the recipient’s phone number.
When the temperature goes below the threshold, I’ll receive another SMS.
This tutorial focus on programming the ESP32 using the Arduino core, so before proceeding, you should have the ESP32 add-on installed in your Arduino IDE.
Follow the next tutorial to install the ESP32 on the Arduino IDE, if you haven’t already.
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux instructions)
Alternatively, you can also use VS Code with the PlatformIO extension to program your boards using the Arduino core:
Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266 (Windows, Mac OS X, Linux Ubuntu)
You can have only one master, which will be a microcontroller (the ESP32), but you can have multiple slaves.
A slave can be a sensor, a display, a microSD card, etc., or another microcontroller.
This means you can have an ESP32 connected to multiple sensors, but the same sensor can’t be connected to multiple ESP32 boards simultaneously.
| GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 | |
| GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
To select the peripheral you want to communicate with, you should set its CS pin to LOW.
For example, imagine you have peripheral 1 and peripheral 2.
To read from peripheral 1, make sure its CS pin is set to LOW (here represented as CS_1):
digitalWrite(CS_1, LOW); // enable CS pin to read from peripheral 1
/*
use any SPI functions to communicate with peripheral 1
*/
Then, at same point, you’ll want to read from peripheral 2.
You should disable peripheral 1 CS pin by setting it to HIGH, and enable peripheral 2 CS pin by setting it to LOW:
digitalWrite(CS_1, HIGH); // disable CS pin from peripheral 1
digitalWrite(CS_2, LOW); // enable CS pin to read from peripheral 2
/*
use any SPI functions to communicate with peripheral 2
*/
Briefly, to use HSPI and VSPI simultaneously, you just need to.
As you can see, it prints the IP address
In our case, the ESP32 MAC Address is
The Wi-Fi Manager allows you to connect the ESP32 boards to different Access Points (networks) without having to hard-code network credentials (SSID and password) and upload new code to the board.
Your ESP will automatically join the last saved network or set up an Access Point that you can use to configure the network credentials.
By following this project, you’ll learn more about the following concepts:
Controlling two addressable RGB LED “strips” individually with the ESP32;
Build a Web Server with the ESP32 using Server-sent Events (SSE);
Handle HTML input fields to save data on your board (SSID and password);
Save variables permanently using files on the filesystem;
Build your own Wi-Fi Manager using the ESPAsyncWebServer library;
Switch between station mode and access point mode;
And much more…
To better understand how this project works, we recommend taking a look at the following tutorials:
Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE
How to Set an ESP32 Access Point (AP) for Web Server
ESP32 Static/Fixed IP Address
ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)
If you want to follow this project and have a different ESP32 model, you can assemble the circuit on a breadboard, or you can modify the PCB layout and wiring to match the pinout of your ESP32 board.
Throughout this project, we provide all the necessary files if you need to modify the PCB.
Additionally, you can follow this project by assembling the circuit on a breadboard if you don’t want to build a PCB shield.
The shield consists of:
BME280 temperature, humidity, and pressure sensor;
Pushbutton;
Two rows of 5 addressable RGB LEDs (WS2812B).
If you replicate this project on a breadboard, instead of individual WS2812B addressable RGB LEDs, you can use addressable RGB LED strips .
| BME280 | GPIO 21 (SDA), GPIO 22 (SCL) |
| Pushbutton | GPIO 18 |
| Addressable RGB LEDs (row 1) | GPIO 27 |
| Addressable RGB LEDs (row 2) | GPIO 32 |
When the board is in Access Point mode (Wi-Fi Manager), all LEDs are lit in red.
When the board is in station mode (Web Server with sensor readings), all LEDs are temporarily lit in green/teal color before showing the temperature and humidity range.
*We ended up not using the pushbutton for this particular project, so, it is not necessary to include it in your circuit.
Turn your DIY breadboard circuits into professional PCBs – get 10 boards for approximately $5 + shipping (which will vary depending on your country).
Once you have your Gerber files, you can order the PCB.
Follow the next steps.
1.
Download the Gerber files –
3.
PCBWay can grab all the PCB details and automatically fills them for you.
Use the “Quick-order PCB (Autofill parameters)”.
4.
Press the “+ Add Gerber file” button to upload the provided Gerber files.
And that’s it.
You can also use the OnlineGerberViewer to check if your PCB is looking as it should.
As usual, everything comes well packed, and the PCBs are really high-quality.
The letters on the silkscreen are really well-printed and easy to read.
We’re really satisfied with the PCBWay service.
Here are some other projects we’ve built using the PCBWay service:
ESP32-CAM with Telegram: Take Photos, Control Outputs, Request Sensor Readings and Motion Notifications
ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors
DOIT ESP32 DEVKIT V1 Board (
Start by soldering the SMD components.
Then, solder the header pins.
And finally, solder the other components or use header pins if you don’t want to connect the components permanently.
Here’s how the ESP32 Shield looks like after assembling all the parts.
The ESP32 board should stack perfectly on the header pins on the other side of the PCB.
When the ESP first starts, it tries to read the ssid.txt, pass.txt, and ip.txt files (
You should save the HTML, CSS, and JavaScript files inside a folder called
We want to send the submitted values on the input fields to the server when we click on the Submit button.
Here’s the HTML form with the three input fields:
<form action="/" method="POST">
<p>
<label for="ssid">SSID</label>
<input type="text" id ="ssid" name="ssid"><br>
<label for="pass">Password</label>
<input type="text" id ="pass" name="pass"><br>
<label for="ip">IP Address</label>
<input type="text" id ="ip" name="ip" value="192.168.1.200">
<input type ="submit" value ="Submit">
</p>
</form>
This is the input field for the SSID:
<label for="ssid">SSID</label>
<input type="text" id ="ssid" name="ssid"><br>
The input field for the password:
<label for="pass">Password</label>
<input type="text" id ="pass" name="pass"><br>
The HTML form contains different form elements.
All the form elements are enclosed inside this <form> tag.
It contains controls (the input fields) and labels for those controls.
Additionally, the <form> tag must include the action attribute that specifies what you want to do when the form is submitted (it redirects to the / root URL, so that we remain on the same page).
In our case, we want to send that data to the server (ESP32) when the user clicks the
All the LEDs on the shield will be lit in red, indicating that the board is set as an access point.
On your computer or smartphone, go to your network settings and connect to the
Then, open your browser and go to 192.168.4.1.
The Wi-Fi Manager web page should open.
Enter your network credentials: SSID and Password and an available IP address on your local network.
After that, you’ll be redirected to the following page:
At the same time, the ESP should print the following in the Serial Monitor indicating that the parameters you’ve inserted were successfully saved on the corresponding files:
After a few seconds, the ESP will restart.
And if you’ve inserted the right SSID and password it will start in station mode:
All the LEDs on the shield will be lit in a teal color for 30 seconds.
This time, open a browser on your local network and insert the ESP IP address.
You should get access to the web page that displays the sensor readings:
The LEDs on the shield will light up accordingly to the temperature and humidity range.
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)
We have tutorials for other motors with the ESP32:
ESP32 with
Stepper motors are made of internal coils that make the motor shaft move in steps in one direction or the other when current is applied to the coils in a specific way.
There are two types of stepper motors: unipolar and bipolar stepper motors.
In this article, we won’t detail how the stepper motors are made and how they work internally.
To learn in more detail how they work and the differences between each type of stepper motor, we recommend reading this article by the DroneBotWorkshop blog .
The 28BYJ-48 Stepper Motor has a stride angle of 5.625°/64 in half-step mode.
This means that the motor has a step angle of 5.625o—so it needs 360o/5.625o = 64 steps in half-step mode.
In full-step mode: 64/2 = 32 steps to complete one rotation.
However, the output shaft is driven via a 64:1 gear ratio.
This means that the shaft (visible outside the motor) will complete a rotation if the motor inside rotates 64 times.
This means that the motor will have to move 32×64 = 2048 steps for the shaft to complete one full rotation.
This means that you’ll have a precision of 360o/2048 steps = 0.18o/step.
So, in summary:
Total steps per revolution = 2048 steps
Step angle = 0.18o/step
If you’re using a different stepper motor, please consult the datasheet.
The module comes with a connector that makes it easy and simple to connect the motor to the module.
It has four input pins to control the coils that make the stepper motor move.
The four LEDs provide a visual interface of the coils’ state.
There are pins to connect VCC and GND, and a jumper cap that acts as an ON/OFF switch to power the stepper motor—if you remove the jumper, there is no power reaching the motor.
You can use those pins to wire a physical switch.
| IN1 | Control the motor: connect to a microcontroller digital pin |
| IN2 | Control the motor: connect to a microcontroller digital pin |
| IN3 | Control the motor: connect to a microcontroller digital pin |
| IN4 | Control the motor: connect to a microcontroller digital pin |
| VCC | Powers the motor |
| GND | Common GND |
| Motor connector | Connect the motor connector |
| IN1 | GPIO 19 |
| IN2 | GPIO 18 |
| IN3 | GPIO 5 |
| IN4 | GPIO 17 |
We’ll use the TDS meter from keystudio and show you a simple example to measure TDS in ppm units using Arduino IDE.
In this tutorial, we’ll cover the following topics
Although this is a good indicator to monitor the quality of the water,
You can check the TDS sensor on Maker Advisorto find the best price:
TDS Sensor
| GND | GND |
| VCC | 3.3V |
| Data | GPIO 27 (or any other ESP32 ADC pin ) |
To get more accurate results, you’ll probably need to calibrate your sensor against a solution with a known TDS value.
Also, take into account the non-linearity of the ESP32 ADC when it comes to low and high values.
However, these adjustments might be not needed if you are not concerned about specific values but about a qualitative value of TDS.
Upload the following code to your ESP32.
// Original source code: https://wiki.keyestudio.com/KS0429_keyestudio_TDS_Meter_V1.0#Test_Code
// Project details: https://RandomNerdTutorials.com/esp32-tds-water-quality-sensor/
#define TdsSensorPin 27
#define VREF 3.3 // analog reference voltage(Volt) of the ADC
#define SCOUNT 30 // sum of sample point
int analogBuffer[SCOUNT]; // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;
int copyIndex = 0;
float averageVoltage = 0;
float tdsValue = 0;
float temperature = 25; // current temperature for compensation
// median filtering algorithm
int getMedianNum(int bArray[], int iFilterLen){
int bTab[iFilterLen];
for (byte i = 0; i<iFilterLen; i++)
bTab[i] = bArray[i];
int i, j, bTemp;
for (j = 0; j < iFilterLen - 1; j++) {
for (i = 0; i < iFilterLen - j - 1; i++) {
if (bTab[i] > bTab[i + 1]) {
bTemp = bTab[i];
bTab[i] = bTab[i + 1];
bTab[i + 1] = bTemp;
}
}
}
if ((iFilterLen & 1) > 0){
bTemp = bTab[(iFilterLen - 1) / 2];
}
else {
bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
}
return bTemp;
}
void setup(){
Serial.begin(115200);
pinMode(TdsSensorPin,INPUT);
}
void loop(){
static unsigned long analogSampleTimepoint = millis();
if(millis()-analogSampleTimepoint > 40U){ //every 40 milliseconds,read the analog value from the ADC
analogSampleTimepoint = millis();
analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin); //read the analog value and store into the buffer
analogBufferIndex++;
if(analogBufferIndex == SCOUNT){
analogBufferIndex = 0;
}
}
static unsigned long printTimepoint = millis();
if(millis()-printTimepoint > 800U){
printTimepoint = millis();
for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
// read the analog value more stable by the median filtering algorithm, and convert to voltage value
averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 4096.0;
//temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationCoefficient = 1.0+0.02*(temperature-25.0);
//temperature compensation
float compensationVoltage=averageVoltage/compensationCoefficient;
//convert voltage value to tds value
tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage - 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;
//Serial.print("voltage:");
//Serial.print(averageVoltage,2);
//Serial.print("V ");
Serial.print("TDS Value:");
Serial.print(tdsValue,0);
Serial.println("ppm");
}
}
}
View raw code
It will show a value of 0 if the probe is not submerged.
Put the probe on a solution to check its TDS.
You can try with tap water and add some salt to see if the values increase.
I measured the TDS value for tap water in my house, and I got a value of around 100ppm, which is a good value for drinking water.
I also tested tea, and the TDS value increased to about 230ppm, which seems a reasonable value.
Finally, I also measured the TDS value of bottled water and I got a value of 0ppm.
I’m not sure if this value is correct because the water is advertised as mineral water, so the minerals dissolved in the water should account for a TDS value.
I think this value can be explained due to the non-linearity of the ESP32 ADC pins for small voltage values.
Do you have one of these sensors? What values did you get for bottled water?
ThingSpeak allows you to publish your sensor readings to their website and plot them in charts with timestamps.
Then, you can access your readings from anywhere in the world.
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU Publish Sensor Readings to ThingSpeak (easiest way)
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Press the “New Channel” button to create a new channel.
Type a name for your channel and add a description.
In this example, we’ll just publish temperature.
If you want to publish multiple readings (like humidity and pressure), you can enable more fields as you’ll see later in this tutorial.
Click the
You can give a title to your chart, customize the background color, x and y axis, and much more.
When you’re done, press the “
Go to your ThingSpeak account to the channel you’ve just created, and you’ll see the temperature readings being published and plotted on the chart.
Now, you can get access to those readings from anywhere in the world by accessing your ThingSpeak account.
Finally, save the channel—click the
Now, if you go to the
If you go to your ThingSpeak account, under
To learn more about deep sleep and other wake up sources, you can follow the next tutorials:
Every 5 seconds, the ESP32 wakes up, prints a message on the serial monitor, and goes to deep sleep again.
Every time the ESP32 wakes up, the bootCount variable increases.
It also prints the wake up reason as shown in the figure below.
However, notice that if you press the EN button on the ESP32 board, it resets the boot count to 1 again.
To read the value of the ESP32 touch pins, use the touchRead(GPIO) function, that accepts as argument, the GPIO you want to read.
Learn more about the ESP32 GPIOs: ESP32 Pinout Reference .
You can see that touch sensor 0 corresponds to GPIO 4, touch sensor 2 to GPIO 2, and so on.
You can also use the serial plotter to better see the values.
Close the serial monitor, go to
With the previous code running, go back to the serial monitor.
Now, touch the aluminium foil, and you’ll see the values changing again.
In our case, when we’re not touching the pin, the normal value is above 70.
And when we touch the aluminum foil it drops to some value below 10.
So, we can set a threshold value, and when the reading goes below that value, an LED lights up.
A good threshold value in this case is 20, for example.
The ESP32 can be awake from deep sleep using several wake up sources: timer, external wake up and touch wake up.
This article shows how to use touch wake up.
To learn more about deep sleep and other wake up sources, you can follow the next tutorials:
You can see that touch sensor 0 corresponds to GPIO 4, touch sensor 2 to GPIO 2, and so on.
(This schematic uses the ESP32 DEVKIT V1 module version with 30 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
If at this moment you can’t find your ESP32 board name, we recommend repeating the installation process from scratch.
Press the “
After you see the“
After that, you should see the “
And it fails to compile with a similar error message:
In function ‘void setup()’:
ScanNetworks:52: error: ‘class WiFiClass’ has no member named ‘firmwareVersion’
String fv = WiFi.firmwareVersion();
It looks like your Arduino IDE is compiling the WiFi library for the Arduino board (instead of using the ESP32 WiFi library).
Go to Google and search for your particular chip to find the drivers and install them in your operating system.
You can download the CP2102 drivers on the Silicon Labs website.
After they are installed, restart the Arduino IDE and you should see the COM port in the Tools menu.
| WiFi.mode(WIFI_STA) | station mode: the ESP32 connects to an access point |
| WiFi.mode(WIFI_AP) | access point mode: stations can connect to the ESP32 |
| WiFi.mode(WIFI_AP_STA) | access point and a station connected to another access point |
The router is connected to the internet, so we can request information from the internet using the ESP32 board like data from APIs (weather data, for example), publish data to online platforms, use icons and images from the internet or include JavaScript libraries to build web server pages.
Because the ESP32 doesn’t connect further to a wired network like your router, it is called soft-AP (soft Access Point).
This means that if you try to load libraries or use firmware from the internet, it will not work.
It also doesn’t work if you make HTTP requests to services on the internet to publish sensor readings to the cloud or use services on the internet (like sending an email, for example).
This can be useful to check if the Wi-Fi network you’re trying to connect is within the range of your board or other applications.
Your Wi-Fi project may not often work because it may not be able to connect to your router due to insufficient Wi-Fi strength.
Here’s the example:
/*
Example from WiFi > WiFiScan
Complete details at https://RandomNerdTutorials.com/esp32-useful-wi-fi-functions-arduino/
*/
#include "WiFi.h"
void setup() {
Serial.begin(115200);
// Set WiFi to station mode and disconnect from an AP if it was previously connected
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Setup done");
}
void loop() {
Serial.println("scan start");
// WiFi.scanNetworks will return the number of networks found
int n = WiFi.scanNetworks();
Serial.println("scan done");
if (n == 0) {
Serial.println("no networks found");
} else {
Serial.print(n);
Serial.println(" networks found");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.print(")");
Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
delay(10);
}
}
Serial.println("");
// Wait a bit before scanning again
delay(5000);
}
View raw code
You can upload it to your board and check the available networks as well as the RSSI (received signal strength indicator).
WiFi.scanNetworks() returns the number of networks found.
int n = WiFi.scanNetworks();
After the scanning, you can access the parameters about each network.
WiFi.SSID() prints the SSID for a specific network:
Serial.print(WiFi.SSID(i));
WiFi.RSSI() returns the RSSI of that network.
RSSI stands for
| 0 | WL_IDLE_STATUS | temporary status assigned whenWiFi.begin()is called |
| 1 | WL_NO_SSID_AVAIL | when no SSID are available |
| 2 | WL_SCAN_COMPLETED | scan networks is completed |
| 3 | WL_CONNECTED | when connected to a WiFi network |
| 4 | WL_CONNECT_FAILED | when the connection fails for all the attempts |
| 5 | WL_CONNECTION_LOST | when the connection is lost |
| 6 | WL_DISCONNECTED | when disconnected from a network |
A lower absolute value means a strongest Wi-Fi connection.
| 0 | ARDUINO_EVENT_WIFI_READY | ESP32 Wi-Fi ready |
| 1 | ARDUINO_EVENT_WIFI_SCAN_DONE | ESP32 finishes scanning AP |
| 2 | ARDUINO_EVENT_WIFI_STA_START | ESP32 station start |
| 3 | ARDUINO_EVENT_WIFI_STA_STOP | ESP32 station stop |
| 4 | ARDUINO_EVENT_WIFI_STA_CONNECTED | ESP32 station connected to AP |
| 5 | ARDUINO_EVENT_WIFI_STA_DISCONNECTED | ESP32 station disconnected from AP |
| 6 | ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE | the auth mode of AP connected by ESP32 station changed |
| 7 | ARDUINO_EVENT_WIFI_STA_GOT_IP | ESP32 station got IP from connected AP |
| 8 | ARDUINO_EVENT_WIFI_STA_LOST_IP | ESP32 station lost IP and the IP is reset to 0 |
| 9 | ARDUINO_EVENT_WPS_ER_SUCCESS | ESP32 station wps succeeds in enrollee mode |
| 10 | ARDUINO_EVENT_WPS_ER_FAILED | ESP32 station wps fails in enrollee mode |
| 11 | ARDUINO_EVENT_WPS_ER_TIMEOUT | ESP32 station wps timeout in enrollee mode |
| 12 | ARDUINO_EVENT_WPS_ER_PIN | ESP32 station wps pin code in enrollee mode |
| 13 | ARDUINO_EVENT_WIFI_AP_START | ESP32 soft-AP start |
| 14 | ARDUINO_EVENT_WIFI_AP_STOP | ESP32 soft-AP stop |
| 15 | ARDUINO_EVENT_WIFI_AP_STACONNECTED | a station connected to ESP32 soft-AP |
| 16 | ARDUINO_EVENT_WIFI_AP_STADISCONNECTED | a station disconnected from ESP32 soft-AP |
| 17 | ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED | ESP32 soft-AP assign an IP to a connected station |
| 18 | ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED | Receive probe request packet in soft-AP interface |
| 19 | ARDUINO_EVENT_WIFI_AP_GOT_IP6 | ESP32 access point v6IP addr is preferred |
| 19 | ARDUINO_EVENT_WIFI_STA_GOT_IP6 | ESP32 station v6IP addr is preferred |
| 19 | ARDUINO_EVENT_ETH_GOT_IP6 | Ethernet IPv6 is preferred |
| 20 | ARDUINO_EVENT_ETH_START | ESP32 ethernet start |
| 21 | ARDUINO_EVENT_ETH_STOP | ESP32 ethernet stop |
| 22 | ARDUINO_EVENT_ETH_CONNECTED | ESP32 ethernet phy link up |
| 23 | ARDUINO_EVENT_ETH_DISCONNECTED | ESP32 ethernet phy link down |
| 24 | ARDUINO_EVENT_ETH_GOT_IP | ESP32 ethernet got IP from connected AP |
| 25 | ARDUINO_EVENT_MAX |
There is a method provided by the WiFi.h library that allows you to set a custom hostname.
First, start by defining your new hostname.
For example:
String hostname = "ESP32 Node Temperature";
Then, call the WiFi.setHostname() function before calling WiFi.begin().
You also need to call WiFi.config() as shown below:
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setHostname(hostname.c_str()); //define hostname
You can copy the complete example below:
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-set-custom-hostname-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <WiFi.h>
// Replace with your network credentials (STATION)
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
String hostname = "ESP32 Node Temperature";
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
WiFi.setHostname(hostname.c_str()); //define hostname
//wifi_station_set_hostname( hostname.c_str() );
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
Serial.print("RRSI: ");
Serial.println(WiFi.RSSI());
}
void loop() {
// put your main code here, to run repeatedly:
}
View raw code
You can use this previous snippet of code in your projects to set a custom hostname for the ESP32.
If you’re using Arduino IDE follow this tutorial instead: Install ESP32 Filesystem Uploader in Arduino IDE .
Then, select the newly created data folder and create the files you want to upload by clicking on the
Write some random text inside that .txt file.
The data folder should be under the project folder and the files you want to upload should be inside the data folder.
Otherwise, it won’t work.
This error means that you have a serial connection opened with your board in VS Code or in any other program.
Close any program that might be using the board serial port, and make sure you close all serial connections in VS Code (click on the recycle bin icon on the terminal console).
If you start seeing a lot of dots on the debugging window and the filesystem image fails to upload, you need to press the on-board boot button once you start seeing the dots.
To solve this issue permanently, read the following article:
[SOLVED] Failed to connect to ESP32: Timed out waiting for packet header
You’ve successfully uploaded files to the ESP32 filesystem (SPIFFS) using VS Code + PlatformIO.
If you want to follow this project and you have a different ESP32 model, you can assemble the circuit on a breadboard or you can modify the PCB layout and wiring to match the pinout of your ESP32 board.
Throughout this project, we provide all the necessary files, if you need to modify the PCB.
The shield consists of:
BME280 temperature, humidity and pressure sensor;
LDR (light dependent resistor – luminosity sensor);
0.96 inch I2C OLED Display;
Pushbutton;
12 WS2812B addressable RGB LEDs;
If you’re going to replicate this project on a breadboard, instead of individual WS2812B addressable RGB LEDs, you can use an addressable RGB LED strip or an addressable RGB LED ring with the same number of LEDs (12).
| BME280 | GPIO 21 (SDA), GPIO 22 (SCL) |
| OLED Display | GPIO 21 (SDA), GPIO 22 (SCL) |
| Light Dependent Resistor (LDR) | GPIO 33 |
| Pushbutton | GPIO 18 |
| Addressable RGB LEDs | GPIO 27 |
The OLED displays five different screens:
Current date and time;
Temperature
Humidity
Pressure
Luminosity
Each screen is shown for 15 seconds before going to the next one.
Alternatively, you can press the pushbutton to change screens.
In each screen the WS2812B addressable RGB LEDs show a different pattern:
On the date and time screen, the RGB LEDs display a rainbow effect;
On the other screens, the RGB LEDs work like a gauge.
For example, 100% humidity lights up all LEDs, 50% humidify lights up half of the number of LEDs.
The color of the LEDs is different for each screen: green for the temperature, blue for the humidity, purple for pressure and yellow for luminosity.
Having the parts assigned, place each component.
When you’re happy with the layout, make all the connections and route your PCB.
Save your project and export the Gerber files.
Turn your DIY breadboard circuits into professional PCBs – get 10 boards for approximately $5 + shipping (which will vary depending on your country).
Once you have your Gerber files, you can order the PCB.
Follow the next steps.
1.
Download the Gerber files –
3.
PCBWay can grab all the PCB details and automatically fills them for you.
Use the “Quick-order PCB (Autofill parameters)”.
4.
Press the “+ Add Gerber file” button to upload the provided Gerber files.
And that’s it.
You can also use the OnlineGerberViewer to check if your PCB is looking as it should.
If you aren’t in a hurry, you can use the China Post shipping method to lower your cost significantly.
In our opinion, we think they overestimate the China Post shipping time.
You can increase your PCB order quantity and change the solder mask color.
I’ve ordered the Blue color.
Once you’re ready, you can order the PCBs by clicking “Save to Cart” and complete your order.
As usual, everything comes well packed, and the PCBs are really high-quality.
The letters on the silkscreen are really well-printed and easy to read.
Additionally, the solder sticks easily to the pads.
We’re really satisfied with the PCBWay service.
Here’s some other projects we’ve built using the PCBWay service:
ESP32-CAM with Telegram: Take Photos, Control Outputs, Request Sensor Readings and Motion Notifications
ESP32 IoT Shield PCB with Dashboard for Outputs and Sensors
DOIT ESP32 DEVKIT V1 Board (
Read our review about the TS80 Soldering Iron: TS80 Soldering Iron Review – Best Portable Soldering Iron .
Start by soldering the SMD components.
Then, solder the header pins.
And finally, solder the other components or use header pins if you don’t want to connect the components permanently.
Here’s how the ESP32 Shield looks like after assembling all the parts.
The ESP32 board should stack perfectly on the header pins on the other side of the PCB.
For a complete demonstration, we recommend watching the following video.
One of the key advantages of Web BLE is its cross-platform compatibility.
Unlike traditional mobile apps developed for Android or iOS, Web BLE applications are web-based and can run on any device with a modern web browser that supports Web BLE.
This cross-platform compatibility removes the need for users to download and install dedicated mobile apps, simplifying the user experience and reducing development efforts.
This means you can use a smartphone, tablet, or desktop computer to connect and control ESP32 devices using a Web BLE application.
The Web Bluetooth API is still under development, but it is generally considered to be stable and usable.
It has been implemented in Chrome, Edge, Opera, and Firefox, and it is supported on Android and Windows.
In our particular example, the ESP32 takes the role of the BLE Peripheral, serving as the device that provides data or services.
Your smartphone or computer acts as the BLE Controller, managing the connection and communication with the ESP32.
The server advertises its existence, so it can be found by other devices and contains data that the client can read or interact with.
The client scans the nearby devices, and when it finds the server it is looking for, it establishes a connection and can interact with that device by reading or writing on its characteristics.
The ESP32 GATT structure will have one service with two characteristics.
One characteristic (let’s call it sensor characteristic) will be the place to save a value that changes over time (like sensor readings).
The other characteristic (let’s call it LED characteristic) will be the place to save the state of a GPIO.
By changing the value of that characteristic, we’ll be able to control an LED connected to that GPIO.
The ESP32 will write a new value to the sensor characteristic periodically.
Your browser will connect to the ESP32 Bluetooth device and will receive notifications whenever the value changes and will display the new value on the web page (see Fetched Value in the picture below).
Additionally, your browser will also connect to the LED characteristic and will change its value (see the ON and OFF buttons above).
The ESP32 checks that the value of that characteristic changed, and it will change the state of the GPIO accordingly, turning the LED either on or off.
Now that you’ve set the ESP32 as a BLE Client, we’ll create the web app so that we can interact with the ESP32 via Bluetooth using our web browser.
Alternatively, you can use our web app by going to this URL:
https://ruisantosdotme.github.io/esp32-web-ble
Connect to your ESP32 BLE device and see the values sent by the ESP32 being displayed on the interface and control the ESP32 on-board LED with the ON and OFF buttons.
If you want to learn how to build the web app, continue reading.
With the ESP32 running the code we’ve provided previously, let’s test the web app.
Start by clicking on the Connect to BLE Device button.
A window will pop up and you should see the ESP32 BLE Device.
Connect to that device.
You’ll see that the BLE Status will change to connected and you’ll start receiving the values written by the ESP32 on the sensor characteristic.
Simultaneously, you should get the following messages on the Arduino Serial Monitor showing that the connection was successful and the values being written on the sensor characteristic.
Getting back to the app, if you click the ON and OFF buttons you’ll be able to control the ESP32 LED on and off.
On the Serial Monitor, you’ll see that it detects the changes in the LED characteristic value.
Consequently, it will control the ESP32 onboard LED according to the value written on that characteristic.
2.
The following page will load.
Give a name to your repository, and make sure it is set to
3.
Then, click on
4.
Then, click on
5.
Then, go to
After submitting, wait a few minutes for the web page to be available.
Your web app will be in the following domain:
YOUR_GITHUB_USERNAME.github.io/YOUR_REPOSITORY_NAME
In my case, it is available on the following domain:
https://ruisantosdotme.github.io/esp32-web-ble/
Now you can access the Web App on your smartphone or tablet and control your ESP32 BLE Device from there.
3) Select the COM port in
4) Press the
5) Wait for the “
Press the ESP32 EN button (reset).The ESP32 connects to Wi-Fi, and outputs the ESP IP address on the Serial Monitor.
Copy that IP address, because you need it to access the ESP32 web server.
If you take a look at the Serial Monitor, you can see what’s happening on the background.
The ESP receives an HTTP request from a new client (in this case, your browser).
You can also see other information about the HTTP request.
At the same time, you can take a look at the Serial Monitor to see what’s going on in the background.
For example, when you click the button to turn GPIO 26 ON, ESP32 receives a request on the
When the ESP32 receives that request, it turns the LED attached to GPIO 26 ON and updates its state on the web page.
The button for GPIO 27 works in a similar way.
Test that it is working properly.
We have a similar tutorial for the ESP8266 board: Web Server – Display Sensor Readings in Gauges
To learn more about SSE, you can read:
ESP32 Web Server using Server-Sent Events (Update Sensor Readings Automatically)
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
You should save the HTML, CSS, and JavaScript files inside a folder called
Inside that folder, you should save the HTML, CSS, and JavaScript files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your network credentials.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
You can also check your gauges using your smartphone (the web page is mobile responsive).
If you want to build a web server with files from SPIFFS, follow the next tutorial instead:
ESP32 Web Server using SPIFFS (SPI Flash File System)
The web server is built using the ESPAsyncWebServer library ;
The HTML, CSS, and favicon files are saved on the microSD card;
The microSD card communicates with the ESP32 via SPI communication protocol;
When the client makes a request to the ESP32, it serves the files saved on the microSD card;
You can apply what you’ll learn here to any web server project that you are working on.
| 3V3 | 3.3V |
| CS | GPIO 5 |
| MOSI | GPIO 23 |
| CLK | GPIO 18 |
| MISO | GPIO 19 |
| GND | GND |
For this tutorial you need the following parts:
ESP32 (read Best ESP32 development boards )
MicroSD card module
MicroSD card
Breadboard
Jumper wires
Open a browser on your local network and paste the ESP32 IP address.
It will load the following web page with the files saved on the microSD card.
As an example, we’ll build a web server that displays sensor readings from a BME280 temperature, humidity and pressure sensor.
To learn more about the BME280, read our guide:
ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)
We also have a similar Server-Sent Events guide for the ESP8266 .
The client initiates the SSE connection and the server uses the event source protocol to send updates to the client.
The client will receive updates from the server, but it can’t send any data to the server after the initial handshake.
This is useful to send updated sensor readings to the browser.
Whenever a new reading is available, the ESP32 sends it to the client and the web page can be updated automatically without the need for further requests.Instead of sensor readings, you can send any data that might be useful for your project like GPIO states, notifications when motion is detected, etc.
The ESP32 web server displays three cards with BME280 temperature, humidity and pressure readings;
The ESP32 gets new readings from the sensor every 30 seconds;
Whenever a new reading is available, the board (server) sends it to the client using server-sent events;
The client receives the data and updates the web page accordingly;
This allows the web page to be updated automatically whenever new readings are available.
The client initiates the SSE connection and the server uses the event source protocol on the /events URL to send updates to the client;
The ESP32 gets new sensor readings;
It sends the readings as events with the following names to the client: ‘temperature’, ‘humidity’ and ‘pressure’;
The client has event listeners for the events sent by the server and receives the updated sensor readings on those events;
It updates the web page with the newest readings.
To use the BME280 library, you also need to install the Adafruit Unified Sensor .
Follow the next steps to install the library in your Arduino IDE:
3.
Search for “
After installing the libraries, restart your Arduino IDE.
To learn more about the BME280 sensor, read our guide: ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity) .
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
Open a browser on your local network and insert the ESP32 IP address.
You should get access to the web page to monitor the sensor readings.
The readings are updated automatically every 30 seconds.
At the same time, you should get new sensor readings on the Serial Monitor as shown in the previous print screen.
Additionally, you can check if the client is receiving the events.
On your browser, open the console by pressing
Additionally, you can also modify the code in this tutorial to add slider to your projects to set a threshold value or any other value that you need to use in your code.
The web page for this project is pretty simple.
It contains one heading, one paragraph and one input of type range.
Let’s see how the web page is created.
All the HTML text with styles included is stored in the index_html variable.
Now we’ll go through the HTML text and see what each part does.
The following <meta> tag makes your web page responsive in any browser.
<meta name="viewport" content="width=device-width, initial-scale=1">
Between the <title> </title> tags goes the title of our web server.
The title is the text that shows up on the web browser tab.
Move the slider and see the ESP32 built-in LED increasing and decreasing its brightness.
For demonstration purposes, the web server we’ll build controls an ESP32 output, but it can be easily adapted for other purposes like displaying sensor readings.
The web server you’ll build controls an LED connected to the ESP32 GPIO 2.
This is the ESP32 on-board LED.
You can control any other GPIO;
The web server page shows two buttons: ON and OFF – to turn GPIO 2 on and off;
The web server page also shows the current GPIO state.
The following figure shows a simplified diagram to demonstrate how everything works.
The ESP32 runs a web server code based on the ESPAsyncWebServer library ;
The HTML and CSS files are stored on the ESP32 SPIFFS (Serial Peripheral Interface Flash File System);
When you make a request on a specific URL using your browser, the ESP32 responds with the requested files;
When you click the ON button, you are redirected to the root URL followed by
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 “
You can also modify the code presented in this tutorial to add sliders to your projects to set threshold values or any other values you need to use in your code.
For this project, the ESP32 board will be programmed using the Arduino core.
You can either use the Arduino IDE , VS Code with PlatformIO , or any other suitable IDE.
To better understand how this project works, we recommend taking a look at the following tutorials:
ESP32 PWM with Arduino IDE (Analog Output)
ESP32 WebSocket Server: Control Outputs (Arduino IDE)
ESP32 Web Server with Slider: Control LED Brightness (PWM) *
* This project shows how to build a web server with one slider, but it uses HTTP requests—in this tutorial, we’ll use WebSocket protocol.
We have a similar tutorial for the ESP8266 NodeMCU board:
ESP8266 NodeMCU Web Server (WebSocket) with Multiple Sliders: Control LEDs Brightness (PWM)
The web page contains three cards;
Each card has a paragraph to display the card title (
The server (ESP) receives the slider number and corresponding value and adjusts the PWM duty cycle accordingly.
Additionally, it also notifies all the other clients with the new current slider values—this allows us to have all clients updated almost instantaneously.
The ESP32 outputs the PWM signal with the corresponding duty cycle to control the LED brightness.
A duty cycle of 0% means the LED is completely off, a duty cycle of 50% means the LED is half lit, and a duty cycle of 100% means the LED is lit;
Whenever you open a new web browser window (this is when a new client connects), it will send a message to the ESP32 (also through WebSocket protocol) with the message getValues.
When the ESP32 gets this message, it sends the current slider values.
This way, whenever you open a new tab, it always shows the current and updated values.
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
You should save the HTML, CSS, and JavaScript files inside a folder called
Inside that folder you should save the HTML, CSS and JavaScript files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your network credentials.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
Move the sliders to control the brightness of the LEDs.
Open several tabs or connect to the web server using another device, and notice that the slider values update almost instantaneously whenever there’s a change.
You can watch the video demonstration:
Before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE.
Follow one of the following tutorials to install the ESP32 on the Arduino IDE, if you haven’t already.
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux instructions)
The sensor can communicate using either SPI or I2C communication protocols (there are modules of this sensor that just communicate with I2C, these just come with four pins).
To use SPI communication protocol, you use the following pins:
SCK – this is the SPI Clock pin
SDO– MISO
SDI– MOSI
CS– Chip Select
To use I2C communication protocol, the sensor uses the following pins:
SCK– this is also the SCL pin
SDI– this is also the SDA pin
(This schematic uses the ESP32 DEVKIT V1 module version with 36 GPIOs – if you’re using another model, please check the pinout for the board you’re using.)
After installing the libraries, restart your Arduino IDE.
After installing the BME280 library, and the Adafruit_Sensor library, open the Arduino IDE and, go to | HSPI | GPIO 13 | GPIO 12 | GPIO 14 | GPIO 15 |
| VSPI | GPIO 23 | GPIO 19 | GPIO 18 | GPIO 5 |
The table doesn’t have any styles applied.
You can use CSS to style the table with your own preferences.
You may found this link useful: CSS Styling Tables .
Open your browser, paste the IP address, and you should see the latest sensor readings.
To update the readings, you just need to refresh the web page.
If you like this project you may also like the following tutorials:
Build an All-in-One ESP32 Weather Station Shield
ESP32 Publish Sensor Readings to Google Sheets (ESP8266 Compatible)
ESP32 Data Logging Temperature to MicroSD Card
ESP32 with Multiple DS18B20 Temperature Sensors
This is an excerpt from our course: Learn ESP32 with Arduino IDE .
If you like ESP32 and you want to learn more, we recommend enrolling in Learn ESP32 with Arduino IDE course .
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU WebSerial Web-based Remote Serial Monitor
For this tutorial, we’ll use the WebSerial library .
If you like this library and you’ll use it in your projects, consider supporting the developer’s work .
You also need to install the ESPAsyncWebServer and the AsyncTCP libraries.
Click the following links to download the libraries’ files.
ESPAsyncWebServer
AsyncTCP
To install these libraries, click on the previous links to download the libraries’ files.
Then, in your Arduino IDE, go to
Now, open a browser on your local network and type the ESP IP address followed by /webserial.
For example, in my case:
192.168.1.85/
As you can see, it is printing Hello! every two seconds.
Additionally, you can send commands to the ESP32.
All the commands that you send are printed back on the web serial monitor.
You can send the ON and OFF commands to control the built-in LED.
This was just a simple example showing how you can use the WebSerial library to create a web-based serial monitor to send and receive data.
Now, you can easily add a web-based serial monitor to any of your projects using the WebSerial library .
The ESP32 will be programmed using Arduino IDE and the ESPAsyncWebServer.
We also have a similar WebSocket guide for the ESP8266 .
If you’ve been following some of our previous web server projects like this one , you may have noticed that if you have several tabs (in the same or on different devices) opened at the same time, the state doesn’t update in all tabs automatically unless you refresh the web page.
To solve this issue, we can use WebSocket protocol – all clients can be notified when a change occurs and update the web page accordingly.
This tutorial was based on a project created and documented by one of our readers (Stéphane Calderoni).
You can read his excellent tutorial here .
The client establishes a WebSocket connection with the server through a process known as WebSocket handshake.
The handshake starts with an HTTP request/response, allowing servers to handle HTTP connections as well as WebSocket connections on the same port.
Once the connection is established, the client and the server can send WebSocket data in full duplex mode.
Using the WebSockets protocol, the server (ESP32 board) can send information to the client or to all clients without being requested.
This also allows us to send information to the web browser when a change occurs.
This change can be something that happened on the web page (you clicked a button) or something that happened on the ESP32 side like pressing a physical button on a circuit.
The ESP32 web server displays a web page with a button to toggle the state of GPIO 2;
For simplicity, we’re controlling GPIO 2 – the on-board LED.
You can use this example to control any other GPIO;
The interface shows the current GPIO state.
Whenever a change occurs on the GPIO state, the interface is updated instantaneously;
The GPIO state is updated automatically in all clients.
This means that if you have several web browser tabs opened on the same device or on different devices, they are all updated at the same time.
Here’s what happens when you click on the “Toggle” button:
Click on the “Toggle” button;
The client (your browser) sends data via WebSocket protocol with the “toggle” message;
The ESP32 (server) receives this message, so it knows it should toggle the LED state.
If the LED was previously off, turn it on;
Then, it sends data with the new LED state to all clients also through WebSocket protocol;
The clients receive the message and update the led state on the web page accordingly.
This allows us to update all clients almost instantaneously when a change happens.
Click on the button to toggle the LED.
You can open several web browser tabs at the same time or access the web server from different devices and the LED state will be update automatically in all clients whenever there’s a change.
To learn more about building web servers with the ESP32 from scratch, check out our eBook: Build Web Servers with the ESP32 and ESP8266 .
Throughout this tutorial, we’ll cover the following main topics:
We have a similar tutorial for the ESP8266 board: ESP8266 NodeMCU WebSocket Server: Display Sensor Readings
The client establishes a WebSocket connection with the server through a process known as WebSocket handshake.
The handshake starts with an HTTP request/response, allowing servers to handle HTTP connections as well as WebSocket connections on the same port.
Once the connection is established, the client and the server can send WebSocket data in full duplex mode.
Using the WebSockets protocol, the server (ESP32 board) can send information to the client or to all clients without being requested.
This also allows us to send information to the web browser when a change occurs.
This change can be something that happened on the web page (you clicked a button) or something that happened on the ESP32 side like pressing a physical button on a circuit, or new sensor readings available.
Learn how to control the ESP32 outputs via WebSocket protocol: ESP32 WebSocket Server: Control Outputs (Arduino IDE) .
We’ll create a web page that displays temperature, humidity, and pressure.
The web page displays the latest sensor readings when you open or refresh the web page.
The sensor readings update automatically whenever there’s a new reading available on the ESP32 without the need to refresh the webpage.
The web server works perfectly on multiple clients (multiple web browser tabs on the same device or different devices).
Every 30 seconds, the ESP gets new readings and sends them to all connected clients (all web browser tabs opened) via WebSocket protocol.
The client receives that message and displays the readings on the web page.
Recommended reading: ESP32 Pinout Reference: Which GPIO pins should you use?
You should save the HTML, CSS, and JavaScript files inside a folder called
Inside that folder, you should place the HTML, CSS, and JavaScript files.
Upload those files to the filesystem: go to
Then, upload the code to your ESP32 board.
Make sure you modified the code with your network credentials.
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
The readings update automatically on the web page every 30 seconds.
You can have multiple clients on different web browser tabs or devices and it will update automatically on all clients.
To better understand how this project works, we recommend taking a look at the following tutorials:
Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE
How to Set an ESP32 Access Point (AP) for Web Server
ESP32 Static/Fixed IP Address
We also use this Wi-Fi Manager approach on the following project:
ESP32 Neopixel Status Indicator and Sensor PCB Shield with Wi-Fi Manager
When the ESP first starts, it tries to read the ssid.txt, pass.txt and ip.txt files* (
You should save the HTML and CSS files inside a folder called
Copy the following to the wifimanager.html file.
This creates a web page with a form with three input fields and a
If you’re using VS Code with the PlatformIO extension, follow one of the next tutorials to learn how to upload files to your boards:
ESP32 with VS Code and PlatformIO: Upload Files to Filesystem (SPIFFS)
After successfully uploading the files, upload the code to your board.
On your computer or smartphone, go to your network settings and connect to the
Then, open your browser and go to 192.168.4.1.
The Wi-Fi Manager web page should open.
Enter your network credentials: SSID and Password and an available IP address on your local network.
After that, you’ll be redirected to the following page:
At the same time, the ESP should print something in the Serial Monitor indicating that the parameters you’ve inserted were successfully saved in the corresponding files.
After a few seconds, the ESP will restart.
And if you’ve inserted the correct SSID and password, it will start in station mode:
This time, open a browser on your local network and insert the ESP IP address.
You should get access to the web page to control the outputs:
Using WiFiMulti in your ESP32 IoT projects is useful if your board can have access to more than one Wi-Fi network.
Implementing this feature in your projects is very simple and improves your projects significantly.
If I remove the iPhone hotspot, the connection will be lost and it will connect to the next strongest network on the list.
Unlike Bluetooth which is always on, BLE remains in sleep mode constantly except for when a connection is initiated.
This makes it consume very low power.
BLE consumes approximately 100x less power than Bluetooth (depending on the use case).
Additionally, BLE supports not only point-to-point communication, but also broadcast mode, and mesh network.
Due to its properties, BLE is suitable for applications that need to exchange small amounts of data periodically running on a coin cell.
For example, BLE is of great use in healthcare, fitness, tracking, beacons, security, and home automation industries.
Low power consumption
Short distance transmission
Low bandwidth (small amounts of data)
Ideal for exchanging small amounts of data periodically
Supports point-to-point, broadcast, and mesh network
Learn how to get started with BLE on the ESP32 with our guides:
Getting Started with ESP32 Bluetooth Low Energy (BLE) on Arduino IDE
ESP32 BLE Server and Client (Bluetooth Low Energy)
Bluetooth is a wireless technology standard used for exchanging data between fixed and mobile devices over short distances.
It is optimized for continuous data streaming, while BLE is optimized for short burst data transmission.
It consumes approximately x100 more power than BLE.
Short distance transmission
Optimized for continuous data streaming
Learn how to use Bluetooth Classic with the ESP32:
ESP32 Bluetooth Classic with Arduino IDE – Getting Started
Fast communication protocol
Up to 250-byte payload can be carried
Encrypted and unencrypted communication
Range communication (220 meters in opan en field accordingly to our experiments)
Read our articles about ESP-NOW:
Getting Started with ESP-NOW (ESP32 with Arduino IDE)
ESP-NOW Two-Way Communication Between ESP32 Boards
More ESP-NOW tutorials…
MQTT stands for Message Queuing Telemetry Transport.
It is a lightweight publish and subscribe system where you can publish and receive messages as a client.
MQTT is a simple messaging protocol, designed for constrained devices with low-bandwidth.
To use MQTT to exchange data, you need an MQTT broker that is responsible for receiving all messages, filtering the messages, and publishing the message to all subscribed clients.
MQTT is perfect for IoT projects with multiple devices.
Read our articles about the MQTT communication protocol with the ESP32.
What is MQTT and How It Works
ESP32 MQTT – Publish and Subscribe with Arduino IDE
MicroPython – Getting Started with MQTT on ESP32/ESP8266
LoRa allows long range communication of small amounts of data (which means a low bandwidth), and high immunity to interference while minimizing power consumption.
So, it allows long distance communication with low power requirements.
Long range communication
Low bandwidth (small amounts of data)
High immunity to interference
Low power consumption
To use LoRa with the ESP32 boards, you need a LoRa transceiver chip.
The word “transceiver” means that the chip can send and receive LoRa messages.
There are ESP32 boards that already come with an on-board LoRa transceiver chip , which makes wiring much simpler.
Read our articles about LoRa communication:
ESP32 with LoRa using Arduino IDE – Getting Started – learn what is LoRa, how to connect a LoRa chip to the ESP32, and exchange data between boards.
TTGO LoRa32 SX1276 OLED Board: Getting Started with Arduino IDE – learn how to get started with LoRa with a board with a built-in LoRa chip and OLED display.
ESP32 LoRa Sensor Monitoring with Web Server (Long Range Communication) – set up an ESP32 as a LoRa receiver and as a web server to display received readings.
You can connect your ESP32 board to a modem to be able to send and receive SMS and phone calls and connect to the internet using a SIM card as you would do with your smartphone.
Some of those modems can also get GPS data like latitude, longitude, altitude, and date and time.
There are different modules available that are compatible with the ESP32 and there are also ESP32 boards that already come with a built-in modem and all the necessary circuitry.
We’ve experimented with the ESP32 SIM8000L (2G) , and the ESP32 SIM7000G (3G and 4G) , and we had pretty good results.
To get started with those boards, you can take a look at the following tutorials:
Getting Started with LILYGO
It features a measuring range from 300 to 1100hPa with an accuracy down to 0.02 hPa.
Because temperature affects the pressure, the sensor comes with a temperature sensor to give temperature compensated pressure readings.
Additionally, because the pressure changes with altitude, you can also estimate the altitude based on the current pressure measurement.
| Vin | 3.3V |
| GND | GND |
| SCL | GPIO 22 (SCL) |
| SDA | GPIO 21 (SDA) |
After installing, restart your Arduino IDE.
Then, open the Serial Monitor at a baud rate of 9600.
You should get the sensor readings, as shown in the following figure.
We have a similar tutorial for ESP8266 boards: ESP8266 NodeMCU: Write Data to a File (LittleFS) – Arduino IDE .
Notice that if you restart your board, you’ll lose all your previous data.
Why is that happening?
That happens because we’re calling the writeFile() function in the setup().
As we’ve explained previously, it will create a new file if it doesn’t exist, or overwrite an already existing file with the same name.
To prevent that, we can add some lines to the setup() to check whether the file already exists.
The ESP32 authenticates as a user with email and password to be able to access the database (that user must be added on the Firebase authentication methods);
The database is protected using database rules.
We’ll add the following rule: only authenticated users can access the database;
The database has several nodes that save the ESP32 GPIO states.
As an example, we’ll control three GPIOs (12, 13, and 14).
You can add or remove nodes to control more or less GPIOs.
The ESP32 will listen for changes on the GPIOs database nodes.
Whenever there’s a change, it will update the GPIO states accordingly.
You can change the GPIO states manually on the database using the Firebase console, or you can create a web page (accessible from anywhere) with buttons to control the GPIOs and show the current GPIO states ( check PART 2 ).
These are the main steps to complete this project:
Notice that Firebase creates a unique UID for each registered user.
The user UID allows us to identify the user and keep track of the user to provide or deny access to the project or the database.
There’s also a column that registers the date of the last sign-in.
At the moment, it is empty because we haven’t signed in with that user yet.
Copy the User UID because you’ll need it later.
Copy the user UID of that new user and add it to the database rules, as follows:
{
"rules": {
".read": "auth.uid === 'REPLACE_WITH_YOUR_USER_UID' || auth.uid === 'REPLACE_WITH_USER_UID2'",
".write": "auth.uid === 'REPLACE_WITH_YOUR_USER_UID' || auth.uid === 'REPLACE_WITH_USER_UID2'"
}
}
For example.
In my case, the UIDs of the users are:
All the database nodes required for this project are created.
You can proceed to the next section.
You can use any other suitable ESP32 GPIOs , but you also need to change the database nodes.
Now, you’re all set to start programming the ESP32 boards to interact with the database.
Then, click
Also, change the monitor speed to 115200 by adding the following line to the platformio.ini file of your project:
monitor_speed = 115200
We can get the value of the returned data as follows (knowing beforehand that it is an integer):
int state = data.intData();
Then, we can simply call the digitalWrite() function and pass as arguments the GPIO number and the state to keep the ESP32 output states updated.
digitalWrite(gpio.toInt(), state);
When the ESP first connects to the database, it is triggered on the root(/) path and returns a JSON object with all child nodes.
So, we can get all values from the database and update the ESP32 GPIOs when it first runs.
This is also useful because if the ESP32 resets, it will always receive this JSON object first, and will be able to update all GPIOs.
As you can see from the previous screenshot, the JSON object it receives looks as follows (it might be different depending on the GPIO states):
{
"12": 0,
"13": 0,
"14": 0
}
When this happens, the returned data is of type JSON.
So, we can get it with the following if statement:
if (data.dataTypeEnum() == fb_esp_rtdb_data_type_json){
We can convert the returned data to a FirebaseJSON object:
FirebaseJson json = data.to<FirebaseJson>();
Then, we can iterate through the whole JSON object and get the keys (GPIOs) and corresponding values (GPIO states).
In each iteration, we save the GPIO on the gpio variable and its corresponding state on the state variable.
Then, we call the digitalWrite() function to update its state.
// To iterate all values in Json object
size_t count = json.iteratorBegin();
Serial.println("\n---------");
for (size_t i = 0; i < count; i++){
FirebaseJson::IteratorValue value = json.valueAt(i);
int gpio = value.key.toInt();
int state = value.value.toInt();
Serial.print("STATE: ");
Serial.println(state);
Serial.print("GPIO:");
Serial.println(gpio);
digitalWrite(gpio, state);
Serial.printf("Name: %s, Value: %s, Type: %s\n", value.key.c_str(), value.value.c_str(), value.type == FirebaseJson::JSON_OBJECT ? "object" : "array");
}
Serial.println();
json.iteratorEnd(); // required for free the used memory in iteration (node data collection)
This runs through all keys and values allowing us to update all GPIOs.
Because all our code works with callback functions, we don’t need to place anything on the loop() besides the lines to refresh the Firebase token.
void loop(){
if (Firebase.isTokenExpired()){
Firebase.refreshToken(&config);
Serial.println("Refresh token");
}
}
If the ESP32 needs to perform other tasks, you can add them in the loop().
In our case, this example only listens for database changes.
As you can see, when the ESP first runs, it gets a JSON object with all GPIO states.
{
"12": 0,
"13": 0,
"14": 0
}
Then, go to the Firebase Realtime Database on the Firebase console.
Manually change the GPIO states (either 0 or 1).
After inserting a new value, press Enter.
Right after, you’ll see on the Serial Monitor that the ESP32 detected the changes.
And it will update the GPIO states and light up the LEDs almost instantaneously.
Then, if you reset your board (press the RST button or remove and apply power again), when it restarts, it will get the latest GPIO states from the database and updates them right away.
Now, you can upload the same code to the new board (it is compatible with the ESP32 and ESP8266).
But
In Part 2, we’ll create a Firebase web app so that you have a nice interface to control your GPIOs from anywhere without having to use the Firebase console and change the database manually:
That’s it! Now, you know how to get your ESP32 or ESP8266 board MAC Address.


Updated 29 September 2023
New to the ESP32? You’re in the right place.
This guide contains all the information you need to get started with the ESP32.
Learn what is an ESP32, how to select an ESP32 board, how to get your first program working, and much more.
Here’s what we’ll cover in this guide:
Why are they so popular? Mainly because of the following features:

Previously, we mentioned that the ESP32 is the ESP8266 successor.
These development boards come with all the needed circuitry to power and program the chip, connect it to your computer, pins to connect peripherals, built-in power and control LEDs, an antenna for wi-fi signal, and other useful features.
Others even come with extra hardware like specific sensors or modules, displays, or a camera in the case of the ESP32-CAM.
| 2 (dual core) | |
| 2.4 GHz up to 150 Mbits/s | |
| BLE (Bluetooth Low Energy) and legacy Bluetooth | |
| 32 bits | |
| Up to 240 MHz | |
| 512 KB | |
| 30, 36, or 38 (depending on the model) | |
| Capacitive touch, ADC (analog to digital converter), DAC (digital to analog converter), I2C (Inter-Integrated Circuit), UART (universal asynchronous receiver/transmitter), CAN 2.0 (Controller Area Netwokr), SPI (Serial Peripheral Interface), I2S (Integrated Inter-IC Sound), RMII (Reduced Media-Independent Interface), PWM (pulse width modulation), and more. | |
| RESET and BOOT buttons | |
| built-in blue LED connected to GPIO2; built-in red LED that shows the board is being powered | |
| CP2102 |
It comes with a microUSB interface that you can use to connect the board to your computer to upload code or apply power.
It uses the CP2102 chip (USB to UART) to communicate with your computer via a COM port using a serial interface.
Another popular chip is the CH340.
Check what’s the USB to UART chip converter on your board because you’ll need to install the required drivers so that your computer can communicate with the board (more information about this later in this guide).
This board also comes with a RESET button (may be labeled EN) to restart the board and a BOOT button to put the board in flashing mode (available to receive code).
Note that some boards may not have a BOOT button.
It also comes with a built-in blue LED that is internally connected to GPIO 2.
This LED is useful for debugging to give some sort of visual physical output.
There’s also a red LED that lights up when you provide power to the board.
We have a detailed guide dedicated to the ESP32 GPIOs that we recommend you read: ESP32 Pinout Reference Guide .
It shows how to use the ESP32 GPIOs and explains what are the best GPIOs to use depending on your project.
The placement of the GPIOs might be different depending on your board model.
However, usually, each specific GPIO works in the same way regardless of the development board you’re using (with some exceptions).
For example, regardless of the board, usually GPIO5 is always the VSPI CS0 pin, GPIO 23 always corresponds to VSPI MOSI for SPI communication, etc.
To program your boards, you need an IDE to write your code.
For beginners, we recommend using Arduino IDE.
While it’s not the best IDE, it works well and is simple and intuitive to use for beginners.
After getting familiar with Arduino IDE and you start creating more complex projects, you may find it useful to use VS Code with the Platformio extension instead.
If you’re just getting started with the ESP32, start with Arduino IDE .
At the time of writing this tutorial,
Select your operating system and download the software.
For Windows, we recommend downloading the “
The Arduino IDE window should open.
Enter the following into the “Additional Board Manager URLs” field.
This will add support for ESP32 and ESP8266 boards as well.
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json, http://arduino.esp8266.com/stable/package_esp8266com_index.json
See the figure below.
Then, click the “
Open the
After this, restart your Arduino IDE.
Then, go to
Now, you’re ready to start programming your ESP32 using Arduino IDE.
Connect your ESP32 development board to your computer using a USB cable.
If you have an ESP32 DEVKIT DOIT board, the built-in red LED will turn on.
This indicates the board is receiving power.
3) Press the upload button.
Some boards will automatically go into flashing mode and the code will be successfully uploaded straight away.
Other boards don’t go into flashing mode automatically, so you may end up getting the following error.
Failed to connect to ESP32: Timed out...
Connecting...
Or something like:
A fatal error occurred: Failed to connect to ESP32: Wrong boot mode detected (0x13)! The chip needs to be in download mode.
This means the ESP32 was not in flashing mode when you tried to upload the code.
In this situation, you should long press the board
Press the ESP32 RST or EN button to restart the board and start running the newly uploaded code.
You should get a list of nearby wi-fi networks.
This means everything went as expected.
We have a similar guide for
After downloading the Mac OSX VCP Driver, unzip the installation files.
Open the unzipped folder and double-click the SiLabsUSBDriverDisk.dmg file to start the installation process.
Open the Install CP210x VCP driver file:
Click the “
Follow the installation wizard and complete all the steps.
In some cases, your computer might block the installation, so you need to open your System Settings.
Then, click the “
Finally, you should see the Success message.
In the Arduino IDE, select your ESP32/ESP8266 board USB Port, as shown earlier.
Ours is /dev/cu.SLAB_USBtoUART Serial Port (USB).
That’s it! You should now be able to see the Serial Port of the ESP32/ESP8266 in Arduino IDE.
You can upload a new code to your ESP board to test it.
We have a similar guide for
After downloading the CP210x Windows Drivers, right-click the folder and unzip the installation files.
Open the unzipped folder and double-click the CP210xVCPInstaller_x64.exe file to start the installation process.
Follow the installation wizard, click the “Next” button, and agree with the terms of use to complete the installation process.
The CP210x USB drivers have been installed successfully.
Search for “Device Manager” and open the control panel:
Having an ESP32/ESP8266 board connected to your Windows PC with a USB cable, under the “
In the Arduino IDE, select your ESP32/ESP8266 board COMX Port, as shown earlier.
Ours is COM5 Serial Port (USB).
That’s it! You should now be able to see the COMX Serial Port of the ESP32/ESP8266 in Arduino IDE.
You can upload a new code to your ESP board to test it.
Using Arduino IDE 2.0? Follow this tutorial instead: Arduino IDE 2: Install ESP32 LittleFS Uploader (Upload Files to the Filesystem)
The files were successfully uploaded to the ESP32 filesystem when you see the message “
Follow the next tutorial to flash your ESP boards with the MicroPyhton firmware:
How to flash MicroPython firmware into ESP32/ESP8266
According to the Arduino website: “The Arduino IDE 2.0 is an improvement of the classic IDE, with increased performance, improved user interface and many new features, such as autocompletion, a built-in debugger and syncing sketches with Arduino Cloud“.
If you want to install the ESP32 boards on the “classic” Arduino IDE, follow the next tutorial instead:
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)
If you prefer programming the ESP32 using VS Code + PlatformIO, go to the following tutorial:
Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266 (Windows, Mac OS X, Linux Ubuntu)
If you have doubts, you can go to the Arduino Installation Guide .
4.
Search for
That’s it.
It should be installed after a few seconds.
A new window, as shown below, will open.
Search for your ESP32 board model.
Select the ESP32 board model you’re using, and the COM port.
In our example, we’re using the DOIT ESP32 DEVKIT V1.
Click
After a few seconds, the upload should be complete.
That’s it! You’ve installed the ESP32 Boards successfully in Arduino IDE 2.
3) Select the Port (if you don’t see the COM Port in your Arduino IDE, you need to install the ESP32 CP210x USB to UART Bridge VCP Drivers ):
4) Open the following example under
5) A new sketch opens:
6) Press the
7) If everything went as expected, you should see a “
8) Open the Arduino IDE Serial Monitor at a baud rate of 115200:
9) Press the ESP32 on-board
This is a very basic tutorial that illustrates how to prepare your Arduino IDE for the ESP32 on your computer.
Copy the location from the “
Enter the following into the “Additional Board Manager URLs” field:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Then, click the “OK” button:
Search for
That’s it.
It should be installed after a few seconds.
2.
Select the Port (if you don’t see the COM Port in your Arduino IDE, you need to install theCP210x USB to UART Bridge VCP Drivers ):
3.
Open the following example under
4.
A new sketch opens in your Arduino IDE:
5.
Press the
6.
If everything went as expected, you should see a “
7.
Open the Arduino IDE Serial Monitor at a baud rate of 115200:
8.
Press the ESP32 on-board
Press the “
After you see the“
After that, you should see the “
Besides the SIM7000G module, the board also comes with some interesting features like a battery holder for a 18650 battery, a battery charging circuit where you can connect solar panels to recharge the battery, and a microSD card slot that can be useful for data logging projects or to save configuration settings.
For a more in-depth introduction, we recommend following the getting started guide:
Getting Started with LILYGO T-SIM7000G ESP32 (LTE, GPRS, and GPS)
You also need to install the StreamDebugger library.
Go to
Open the Serial Monitor at a baud rate of 115200 and press the on-board RST button to restart the board.
Place your board outside or next to a window or door so that it can catch satellite signals.
It may take some time until it can get some GPS data, as you can see in the screenshot of my Serial Monitor.
As you can see, it gets latitude, longitude, speed, altitude, visible satellites, number of used satellites to get position, accuracy, and UTC date and time.
The longitude and latitude I got were very accurate.
So, in my case, it was working pretty well to get the location.
It also outputs the complete GNSS navigation information parsed from NMEA sentences (that you can’t see above because the Serial Monitor window is too small).
NMEA stands for National Marine Electronics Association, and in the world of GPS, it is a standard data format supported by GPS manufacturers.
The output is as follows.
The commas separate different values.
1,1,20220809173458.000,41.12XXXX,-8.52XXXX,140.200,0.00,237.6,1,,2.3,2.5,1.0,,20,5,1,,48,,
Here’s what each value means, in order:
GNSS run status
Fix status
UTC date and time
Latitude
Longitude
MSL altitude
Speed over ground
Course over ground
Fix mode
Reserver1
HDOP
PDOP
VDOP
Reserved2
GNSS Satellites in View
GPS Satellites used
GLONASS Satellites used
Reserver3
C/N0 max
HPA
VPA
You can learn more about these parameters and possible values by checking the
Besides the SIM7000G module, the board also comes with some interesting features like a battery holder for an 18650 battery, a battery charging circuit where you can connect solar panels to recharge the battery, and a microSD card slot that can be useful for data logging projects or to save configuration settings.
Here’s a summary of the LILYGO T-SIM7000G ESP32 board features:
Supply voltage: 3.3V DC or 5V DC
ESP32 chip (WROVER-B Module) (240MHz dual-core processor)
Flash memory: 4MB
PSRAM: 8MB
SRAM: 520KB
Built-in Wi-Fi
Built-in Bluetooth
USB to serial converter: CP2104 or CH9102 (drivers)
Built-in SIM7000G module
Built-in nano SIM card slot
Built-in SIM antenna slot
Built-in GPS antenna slot
Built-in Li-ion/Li-Po battery charging circuit:
DW01A battery protection IC
CN3065 solar energy charging interface for 4.4-6.8V solar panel
Built-in 1x 18650 battery holder
Built-in solar panel connector 2p JST-PH
Built-in Micro SD card slot
Built-in on/off switch
To use the capabilities of this board you need to have a nano SIM card with a data plan and a USB-C cable to upload code to the board.
The package includes an external antenna for LTE and another antenna for GPS.
There are two versions of this board (Version 20191227 and Version 20200415).
The picture below shows the two versions.
Visually, they mainly differ on the position of the nano SIM card holder.
The first version had some design issues, so it is recommended to get the latest version.
Aditionally, the latest version comes with some improvements taking into account users’ feedback.
I got my board a long time ago, I’ve got the first version and that’s the one we’ll use throughout this tutorial.
However, this is also compatible with the latest board.
Here’s a list of the improvements on the latest version ( check the documentation ):
Added active GPS antenna power control, when the module GPIO 4 is not turned on, the antenna consumes only the static current of the LDO;
Replaced TP4056 with CN3065 for solar charge input management;
Added reverse battery protection;
Added battery overcharge protection;
Added battery over-discharge protection.
You can check the schematic diagrams for each version on the following links:
LILYGO T-SIM7000G ESP32

| TX | GPIO 26 |
| RX | GPIO 27 |
| POWER | GPIO 4 |
| MOSI | GPIO 15 |
| SCLK | GPIO 14 |
| CS | GPIO 13 |
| MISO | GPIO 2 |
To use LTE and GPRS you needa SIM card with some data plan.
This can be expensive in some countries, so it might be cost-prohibitive depending on how much you can get a data plan for in your country.
You also need to install the StreamDebugger library.
Go to
If you want to test the microSD card features, you should only connect a microSD card, after uploading the code.
Now, you can insert a microSD card, if you want to test the microSD card features.
Then, open the Serial Monitor at a baud rate of 115200.
Press the on-board RST button to restart the board.
Wait some time until the board connects to the network (in my case, it may take up to 2 minutes).
You should get something similar in the Serial Monitor.
You can see that it identifies the microSD card and connects to the network successfully.
Check the preferred mode selection and the preferred selection between CAT-M and NB-IoT.
You’ll need those parameters later, and they differ depending on your SIM card and provider.
Read the voltage from a potentiometer and dim an LED accordingly to the shaft’s position of the potentiometer.
The LED brightness changes when you rotate the potentiometer.

This is especially useful to trigger an action whenever motion is detected or whenever a pushbutton is pressed without the need for constantly checking its state.

After 20 seconds the LED turns off.
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works
ESP#1 publishes messages on the
Now, you can use the library functionalities in your code by importing the library.
On the other side, ESP#1 board should receive the “received” message.
The “received” message is published by ESP#2 on the
The ESP requests temperature and humidity readings from the DHT11 or DHT22 sensor;
Temperature readings are published in the
To use MQTT, you need a broker.
We’ll be using Mosquitto broker installed on a Raspberry Pi.
Read How to Install Mosquitto Broker on Raspberry Pi .
If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works
Now, you can use the library functionalities in your code by importing the library.
If the “Save as…” menu is missing, check that you have properly set up Thonny IDE as in the following tutorial:
Getting Started with Thonny MicroPython (Python) IDE for ESP32 and ESP8266
And that’s it.
The library was uploaded to your board.
To make sure that it was uploaded successfully, go to File > Save as… and select the MicroPython device.
Your file should be listed there:
After uploading the library to your board, you can use the library functionalities in your code by importing the library.
In this example, we’re connecting the DHT data pin to GPIO 14.
However, you can use any other suitable digital pin.
Learn how to use the ESP32 GPIOs with our guide: ESP32 Pinout Reference: Which GPIO pins should you use?
In this example, we’re connecting the DHT data pin toGPIO 14 (D5).
However, you can use any other suitable digital pin.
Learn how to use the ESP8266 GPIOs with our guide: ESP8266 Pinout Reference: Which GPIO pins should you use?
Click the MQTT node and edit its properties.
The Server field refers to the MQTT broker.
In our case, the MQTT broker is the Raspberry Pi, so it is set to localhost:1883.
If you’re using a Cloud MQTT broker, you should change that field.
Insert the topic you want to be subscribed to and the QoS.
This previous MQTT node is subscribed to the
Wire your nodes as shown below:
Finally, deploy your flow (press the button on the upper right corner).
Alternatively, you can go to
That’s it! You have your ESP32 or ESP8266 boards publishing DHT temperature and humidity readings to Node-RED via MQTT using MicroPython.
We’ll take a look at how a relay module works, how to connect the relay to the ESP32 or ESP8266 boards and build a web server to control a relay remotely.
We have similar guides using Arduino IDE:
There are relay modules whose electromagnet can be powered by 5V and with 3.3V.
Both can be used with the ESP32 or ESP8266 – you can either use the VIN pin (that provides 5V) or the 3.3V pin.
Additionally, some come with built-in optocoupler that add an extra “layer” of protection, optically isolating the ESP boards from the relay circuit.
On the left side, there are two sets of three sockets to connect high voltages, and the pins on the right side (low-voltage) connect to the ESP GPIOs.
The relay module shown in the previous photo has two connectors, each with three sockets: common (COM), Normally Closed (NC), and Normally Open (NO).
The low-voltage side has a set of four pins and a set of three pins.
The first set consists of VCC and GND to power up the module, and input 1 (IN1) and input 2 (IN2) to control the bottom and top relays, respectively.
If your relay module only has one channel, you’ll have just one IN pin.
If you have four channels, you’ll have four IN pins, and so on.
The signal you send to the IN pins, determines whether the relay is active or not.
The relay is triggered when the input goes below about 2V.
This means that you’ll have the following scenarios:
The second set of pins consists of GND, VCC, and JD-VCC pins.
The JD-VCC pin powers the electromagnet of the relay.
Notice that the module has a jumper cap connecting the VCC and JD-VCC pins; the one shown here is yellow, but yours may be a different color.
With the jumper cap on, the VCC and JD-VCC pins are connected.
That means the relay electromagnet is directly powered from the ESP power pin, so the relay module and the ESP circuits are not physically isolated from each other.
Without the jumper cap, you need to provide an independent power source to power up the relay’s electromagnet through the JD-VCC pin.
That configuration physically isolates the relays from the ESP with the module’s built-in optocoupler, which prevents damage to the ESP in case of electrical spikes.
In this example, we’re controlling a lamp.
We just want to light up the lamp occasionally, so it is better to use a normally open configuration.
We’re connecting the IN1 pin to GPIO 26, you can use any other suitable GPIO.
See ESP32 GPIO Reference Guide .
We’re connecting the IN1 pin toGPIO 5, you can use any other suitable GPIO.
See ESP8266 GPIO Reference Guide .
The best ESP8266 pins to use with relays are: GPIO 5, GPIO 4, GPIO 14, GPIO 12 and GPIO 13.
Copy the following code to themain.pyfile and upload it to your board.
It lights up your lamp for 10 seconds and turn it off for another 10 seconds.
# Complete project details at https://RandomNerdTutorials.com
from machine import Pin
from time import sleep
# ESP32 GPIO 26
relay = Pin(26, Pin.OUT)
# ESP8266 GPIO 5
#relay = Pin(5, Pin.OUT)
while True:
# RELAY ON
relay.value(0)
sleep(10)
# RELAY OFF
relay.value(1)
sleep(10)
View raw code
In this section, we’ve created a web server example that allows you to control a relay remotely via web server.
Then, open a browser in your local network and type the ESP IP address to get access to the web server.
You should get a web page with a toggle button that allows you to control your relay remotely using your smartphone or your computer.

We recommend that you follow this getting started guide for the OLED display with MicroPython, first: MicroPython OLED Display with ESP32 and ESP8266 .
The file should be saved on the device folder with the name “
Now, you can use the library functionalities in your code by importing the library.
And that’s it.
The library was uploaded to your board.
To make sure that it was uploaded successfully, in the Shell you can type:
%lsdevice
It should return the files currently saved on your board.
One of them should be thessd1306.pyfile.
After uploading the library to your board, you can use the library functionalities in your code by importing the library.
Use the line(x0, y0, x1, y1, color) method on the gfx object to create a line.
The (x0, y0) coordinates indicate the start of the line, and the (x1, y1) coordinates indicate where the line ends.
You always need to call oled.show() to actually display the shapes on the OLED.
Here’s an example:
graphics.line(0, 0, 127, 20, 1)
oled.show()
To draw a rectangle, you can use the rect(x0, y0, width, height, color) method on the gfx object.
The (x0, y0) coordinates indicate the top left corner of the rectangle.
Then, you need to specify the width, height and color of the rectangle.
For example:
graphics.rect(10, 10, 50, 30, 1)
oled.show()
You can use the fill_rect(x0, y0, width, height, color) method to draw a filled rectangle.
This method accepts the same arguments as drawRect().
graphics.rect(10, 10, 50, 30, 1)
oled.show()
Draw a circle using the circle(x0, y0, radius, color) method.
The (x0, y0) coordinates indicate the center of the circle.
Here’s an example:
graphics.circle(64, 32, 10, 1)
oled.show()
Draw a filled circle using the fill_circle(x0, y0, radius, color) method.
graphics.fill_circle(64, 32, 10, 1)
oled.show()
There’s also a method to draw a triangle: triangle(x0, y0, x1, y1, x2, y2, color).
This method accepts as arguments the coordinates of each corner and the color.
graphics.triangle(10,10,55,20,5,40,1)
oled.show()
Use the fill_triangle(x0, y0, x1, y1, x2, y2, color) method to draw a filled triangle.
graphics.fill_triangle(10,10,55,20,5,40,1)
oled.show()
This guide is also fully compatible with the ESP8266 board.
However, since Wi-Fi manager library uses quite a lot of memory you may encounter a memory error while saving the script to your board.
From our experience, restarting the board after uploading the script, removes the error and makes the project work after that.
We recommend using the ESP32, but you can also continue this tutorial using an ESP8266 board.
The file should be saved on the device folder with the name “wifimgr.py” as highlighted in the following figure.
Now, you can use the library functionalities in your code by importing the library.
And that’s it.
The library was uploaded to your board.
To make sure that it was uploaded successfully, in the Shell you can type:
%lsdevice
It should return the files currently saved on your board.
One of them should be thewifimgr.pyfile.
After uploading the library to your board, you can use the library functionalities in your code by importing the library.
That means that the ESP32 was successfully set as an Access Point.
Now, you can connect to that Access Point to choose your network and type your credentials.
To do that, follow the next steps.
In your computer, or smartphone, open the Wi-Fi settings and connect to the
The password is
Once you’re successfully connected to the WiFiManager network, open a browser and type 192.168.4.1.
The following page should load:
Select your network, type the password and click
This message means that your ESP32 is set up as a Wi-Fi Station and it is connected to your local network.
Now, to access the ESP32, go again to your Wi-Fi settings in your computer or smartphone and connect again to your network.
In the Python shell, the ESP32 IP address should be printed.
An
The PCB we’ll build is very versatile and it can be used with an ESP32 , ESP32-CAM , ESP8266 , Arduino or any other microcontroller.
You can power it with a battery, rechargeable batteries + solar panels , or any voltage source.
It can be turned on by different triggers for example from a pushbutton press, motion detected by a PIR sensor , a magnetic reed switch , or any other digital sensor.
You can order a minimum of 5 PCBs for just $2 + shipping which will vary depending on your country.
If you want to turn your breadboard circuits into real boards, you just need to upload the gerber files to order high quality PCBs for a low price.
We’ll show you how to do this later in this tutorial.
You send a HIGH signal to the TRIGGER pin (
To keep your microcontroller powered on, you need to send a HIGH signal from one of its GPIOs to the LATCH pin (labeled as IN) (
When you’re done with that task, you can cut the power by sending a LOW signal to the LATCH PIN (
If you want to customize your PCB, you just need to upload the following files:
EasyEDA project files to edit the PCB
Or you can simply download the Gerber files that I’ve used and order the final PCBs yourself.
In my opinion, the most important step when creating a PCB is to first ensure your circuit actually works on a breadboard or stripboard before designing the circuit.
Creating the circuit works like in any other circuit software tool, you place some components and you wire them together.
When you’re happy with your circuit and pins usage, make sure you assign each component to a footprint.
Having the parts assigned, you can start placing each component and when you’re happy with the layout, make all the connections and route your PCB.
Once you’re done, save your project and generate the Gerber files.
This software allows you to automatically order your PCBs from JLCPCB.
Alternatively, you can also follow the next steps to order the exact PCBs we’ve built.
To build your PCB and follow this tutorial, you need the following parts:
Microcontroller or Development Board, for example:
ESP32 Dev Board ( read ESP32 boards review )
ESP8266 NodeMCU ( read ESP8266 boards review )
Arduino UNO ( read best Arduino Starter Kits )
AO3413 SMD Transistor P-Channel MOSFET
2x 2N3904 SMD TransistorBJT NPN
SMD Resistors: 220K Ohm, 2x 100K Ohm, 2x 10K Ohm, 1K Ohm, 330 Ohm, and 220 Ohm (1206 package)
SMD LED (1206 package)
2x SMD Diodes (for example: 1N5819W)
PIR motion sensor (or reed switch , pushbutton , etc…)
Power Supply
I’ve ordered the PCB components from LCSC , but you can order them from any other electronics store.
As usual, everything comes very well packaged and the PCBs are really high quality, specially the silkscreen.
To solder the PCBs, I’ve used the TS80 soldering iron.
The TS80 soldering iron is the TS100 successor.
I have a review about the TS100 soldering iron .
I didn’t have time yet to write a review about the TS80 , but it’s by far the best portable soldering iron I’ve used.
You can use a similar circuit for other microcontrollers, we’re using an ESP32.
You can use any other trigger like pushbutton, reed switch, or digital sensors with a threshold like smoke sensor, sound sensor, soil moisture sensor, rain sensor, etc…
In the setup(), define the powerLatch and led pins as outputs.
pinMode(powerLatch, OUTPUT);
pinMode(led, OUTPUT);
Next, set the powerLatch pin to HIGH.
When we set it to HIGH, we ensure that
When the ESP32 is on, the whole circuit consumes about 65 mA.
After 10 seconds, the ESP32 turns off.
If we measure the power consumption, you can see that the ESP32 is not consuming any power.
It’s completely powered off.
This would work exactly the same for an ESP8266, Arduino, STM32 or any other microcontroller.
The PIR motion sensor consumes very little power, about 14 uA.
So, even with a small battery it would last years.But if you’re using a pushbutton or a reed switch,
The ESP32-CAM AI-Thinker module is an ESP32 development board with an OV2640 camera, microSD card support, on-board flash lamp and several GPIOs to connect peripherals.
However, it doesn’t have a built-in programmer.
You need an FTDI programmer to connect it to your computer and upload code.
Buy an FTDI Programmer
Buy an ESP32-CAM AI-Thinker with OV2640 Camera
| GND | GND |
| 5V | VCC (5V) |
| U0R | TX |
| U0T | RX |
| GPIO 0 | GND |
5) When you start to see some dots on the debugging window, press the ESP32-CAM on-board RST button.
After a few seconds, the code should be successfully uploaded to your board.
6) When you see the “
This error means that the ESP32-CAM is not in flashing mode or it is not connected properly to the FTDI programmer.
If you get the following error or similar:
serial.serialutil.SerialException: could not open port 'COM8': WindowsError(2, 'The system cannot find the file specified.')
Failed to execute script esptool
the selected serial port Failed to execute script esptool
does not exist or your board is not connected
Board at COM8 is not available
It means that you haven’t selected the COM port in the Tools menu.
In your Arduino IDE, go to
After that, press “
Run the next sequence of commands to check the Python and pip version installed:
On the left menu, open the “
Search for “
Install the “
Press the “
A new window loads that allows you to create a new project for your board, follow these next steps:
Name your project (example: Blink);
Search for “
After the new project is created, you’ll see the project folder on the left menu that you can use to navigate through files and folders.
Open the
The
Here’s a sketch for testing purposes that blinks the LED:
#include <Arduino.h>
// ledPin refers to ESP32 GPIO 23
const int ledPin = 23;
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin ledPin as an output.
pinMode(ledPin, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(ledPin, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(ledPin, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
View raw code
Copy the code to the Atom text editor and follow these next steps to upload code to your ESP32 board:
Connect your ESP32 board to your computer;
Save thew newly created sketch (
Wait a few seconds while the sketch uploads to your board:
After uploading the sketch, your ESP32 should be blinking the LED attached to GPIO 23 every 1 second.
That’s it! The PlatformIO was successfully installed and you can use it to program your ESP32 board.
PlatformIO Home
PlatformIO Build
The PlatformIO software should automatically complete your settings.
Otherwise, select your ESP32 COM port and its baudrate.
Then, press the “
Just like the Arduino IDE Serial Monitor, you have a window that outputs all the Serial.println() commands used in your code:
As you can see, it’s printing the messages: “LED on” and “LED off”.
In this tutorial, we’ll cover the following notification methods:
There are different methods to send emails with the ESP32.
Telegram Messenger is a cloud-based instant messaging and voice-over IP service.
You can easily install it on your smartphone (Android and iPhone) or computer (PC, Mac, and Linux).
It is free and without any ads.
Telegram allows you to create bots that you can interact with.
“Bots are third-party applications that run inside Telegram.
Users can interact with bots by sending them messages, commands, andinline requests.
You control your bots using HTTPS requests to Telegram Bot API“.
So, you just need to make some HTTP requests with the ESP32 to be able to send messages to your Telegram account.
The ESP32 can also listen to messages that you send to your bot.
So, you can also control your boards by sending messages via Telegram.
We have several tutorials showing how to use the Telegram API for different purposes:
Telegram: ESP32
“WhatsApp Messenger, or simply WhatsApp, is an internationally available American freeware, cross-platform centralized instant messaging and voice-over-IP service owned by Meta Platforms.” It allows you to send messages using your phone’s internet connection, so you can avoid SMS fees.
There are different ways to send messages to WhatsApp using the ESP32.
We’ve experimented with the callmebot API and it worked pretty well.
You can check our tutorial that explains how to send messages to WhatsApp with the ESP32:
ESP32: Send Messages to WhatsApp
We also have an example using MicroPython firmware:
MicroPython: Send Messages to WhatsApp with the ESP32/ESP826
Another alternative is to use a third-party service that will send the SMS for you.
You just need to make HTTP requests to their API to use their services.
We have a tutorial showing how to send SMS with the ESP32 using Twilio services (these are not free, but they provide you with some credit so that you can experiment with the service).
Send SMS with the ESP32 (Twilio)
You can send SMS with the ESP32 without the need to rely on third-party services if you have a GSM module and a dedicated SIM card.
We have tutorials showing how to send SMS with the ESP32 using the SIM800L and SIM7000G modules:
ESP32 SIM800L: Send Text Messages (SMS Alert) with Sensor Readings
LILYGO T-SIM7000G ESP32: Connect to the Internet, Send SMS, and Get GPS Data
If you’re looking for different types of notifications and alerts with the ESP32, you can check the following tutorials:
How to send
Twilio provides programmable communication tools for making and receiving phone calls, sending and receiving text messages, and performing other communication functions using its web service APIs.
Throughout this tutorial, we’ll use their programmable messaging services.
Twilio is a paid service, but you can sign-up for a free account for testing purposes.
Then, if their services are useful for your specific project, you can always upgrade your account later on.
We’ll use a free trial account throughout this tutorial.
Enter your details and get started with a free trial.
Give a name to the Messaging Service, for example, ESP32 Alerts and click on
Then, select the Twilio phone number you created previously and click on
After that, the programmable messaging service will be all set up.
You’ll get access to your account information: account SID and Auth token.
You’ll need them later in the ESP32 code.
You can test if everything is working as expected by clicking on
After a few seconds, you should receive the test SMS on the selected number.
All SMS sent from a Twilio trial account will have the text: “Sent from your Twilio trial account”.
This text doesn’t show up on premium accounts.
After uploading, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 RST button to restart the board.
If everything goes as expected, you should receive a similar message as shown below.
After a few seconds, you should receive an SMS from Twilio on your phone.
If you see a similar error in your Arduino IDE or any error related to downloading URLs, cleaning your Arduino IDE installation folder usually solves this issue.
2.
Go to your
3.
Select the
4.
Open the
5.
That’s it! Now, you just need to re-install the ESP32 and ESP8266 board add-ons.
2.
Enter the following URLs into the “A
3.
Open the Boards Manager.
Go to
4.
Search for
5.
Search for
2.
Select the Port (if you don’t see the COM Port in your Arduino IDE, you need to install theCP210x USB to UART Bridge VCP Drivers ):
3.
Open the following example (or any other example) under
4.
A new sketch opens in your Arduino IDE:
5.
Press the
6.
If everything went as expected, you should see a “
If you get the “Timed out waiting for packet header” error, follow this guide: [SOLVED] Failed to connect to ESP32: Timed out waiting for packet header .
7.
Open the Arduino IDE Serial Monitor at a baud rate of 115200:
8.
Press the ESP on-board

Before trying to upload a new code, you should check the connections with a multimeter in continuity mode – check that you haven’t inadvertently solder anything to the next pin.
If everything is soldered properly, you won’t need to press the BOOT button when uploading new code.
You also won’t get the Fatal Error Occurred: “Failed to connect to ESP32: Timed out waiting for packet header”.

We have a similar guide for the ESP8266 NodeMCU board:
[SOLVED] Reconnect ESP8266 NodeMCU to Wi-Fi Network After Lost Connection
You may also want to take a look at WiFiMulti .
It allows you to register multiple networks (SSID/password combinations).
The ESP32 will connect to the Wi-Fi network with the strongest signal (RSSI).
If the connection is lost, it will connect to the next network on the list.
Read: ESP32 WiFiMulti: Connect to the Strongest Wi-Fi Network (from a list of networks) .
This is a didactic tutorial where you’ll learn more about creating web pages and interaction between the ESP32 and the client.
We’ll show you how to create the web page step-by-step with HTML and send the form results to the ESP32 via HTTP POST to control the stepper motor.
Later, you’ll add some CSS to style the web page to improve its look.
Finally, we’ll show you how to use Websockets for bidirectional communication between the server and the client.
This will allow us to know on the web interface whether the motor is spinning or stopped.
This section will add some JavaScript to handle WebSocket communication and add some cool animations to the web page.
The following articles might be useful to understand the concepts covered throughout this tutorial:
ESP32 with Stepper Motor (28BYJ-48 and ULN2003 Motor Driver)
Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE
ESP32 WebSocket Server: Control Outputs (Arduino IDE)
| IN1 | GPIO 19 |
| IN2 | GPIO 18 |
| IN3 | GPIO 5 |
| IN4 | GPIO 17 |
Here’s how it works:
On the web page, you can select whether you want the motor to turn
A radio button is defined as follows:
<input type="radio">
For our project, we need two radio buttons, and only one can be selected at a time.
So, we can create a group of radio buttons.
To do that, the radio buttons must share the same name (the value of the name attribute—in this case direction).
<input type="radio" name="direction">
Finally, we also need the value attribute that specifies a unique value for each radio button.
This value is not visible to the user, but it is sent to the server when you click on the submit button to identify which button was selected.
In our example, we created one radio button with the value CW (to select clockwise) and another CCW (to select counterclockwise).
<input type="radio" name="direction" value="CW">
<input type="radio" name="direction" value="CCW">
Finally, if you want one radio button to be selected by default, you can add the keyword checked.
In our example, the clockwise direction is selected by default.
<input type="radio" name="direction" value="CW" checked>
So, this is how the radio buttons and corresponding labels look like:
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
Finally, we also need an input field where the user enters the number of steps—an input field of type number.
The name attribute allows us to determine in which input field the user entered the data.
<input type="number" name="steps">
Select the direction and enter a determined number of steps.
Then, press GO!.
The stepper motor will start spinning.
At the same time, you can see the values of the direction and steps variables on the Serial Monitor.
When your HTML also includes CSS, it is easier to work if you have separated HTML and CSS files (apart from the Arduino sketch file).
So, instead of writing HTML and CSS in the Arduino sketch, we’ll create separated HTML and CSS files.
These files will then be uploaded to the ESP32 filesystem (SPIFFS) using the
You should save the HTML, CSS, and JavaScript files inside a folder called
Inside that folder, you should save the HTML and CSS files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your network credentials.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
This tutorial is the second part of this article | IN1 | GPIO 19 |
| IN2 | GPIO 18 |
| IN3 | GPIO 5 |
| IN4 | GPIO 17 |
The web page shows a form where you can enter the number of steps you want the motor to move and select the direction: clockwise or counterclockwise.
It also shows the motor state: motor spinning or motor stopped.
Additionally, there’s a gear icon that spins as long as the motor is spinning.
The gear spins clockwise or counterclockwise accordingly to the chosen direction.
The server and the client communicate using WebSocket protocol.
When you click on the
You should save the HTML, CSS, and JavaScript files inside a folder called data inside the Arduino sketch folder, as shown in the previous diagram.
We’ll upload those files to the ESP32 filesystem (SPIFFS).
Inside that folder, you should save the HTML, CSS, and JavaScript files.
Then, upload the code to your ESP32 board.
Make sure you have the right board and COM port selected.
Also, make sure you’ve added your network credentials.
After uploading the code, you need to upload the files.
Go to
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200.
Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
The gear on the web page starts spinning in the right direction and the motor starts working.
When it stops, the gear on the web page and the motor state change accordingly.
Notice that if you have multiple clients connected, all clients update the motor state almost instantaneously.
Watch the video below for a live demonstration.
This tutorial is compatible with ESP32, ESP8266, and Arduino boards.
We’ll program the boards using Arduino IDE.
In this tutorial, we’ll cover the following topics:
The I2C communication protocol allows you to communicate with multiple I2C devices on the same I2C bus as long as all devices have a unique I2C address.
However, it will not work if you want to connect multiple I2C devices with the same address.
The TCA9548A I2C multiplexer allows you to communicate with up to 8 I2C devices with the same I2C bus.
The multiplexer communicates with a microcontroller using the I2C communication protocol.
Then, you can select which I2C bus on the multiplexer you want to address.
To address a specific port, you just need to send a single byte to the multiplexer with the desired output port number.
| LOW | LOW | LOW | 0x70 |
| HIGH | LOW | LOW | 0x71 |
| LOW | HIGH | LOW | 0x72 |
| HIGH | HIGH | LOW | 0x73 |
| LOW | LOW | HIGH | 0x74 |
| HIGH | LOW | HIGH | 0x75 |
| LOW | HIGH | HIGH | 0x76 |
| HIGH | HIGH | HIGH | 0x77 |
| Powers the multiplexer | |
| Connect to GND | |
| Connect to the master microcontroller SDA pin | |
| Connect to the master microcontroller SCL pin | |
| Active low RST pin—can be used to reset the multiplexer | |
| Selects multiplexer I2C address—connect to GND or VCC | |
| Selects multiplexer I2C address—connect to GND or VCC | |
| Selects multiplexer I2C address—connect to GND or VCC | |
| SDA for channel 0 | |
| SCL for channel 0 | |
| SDA for channel 1 | |
| SCL for channel 1 | |
| SDA for channel 2 | |
| SCL for channel 2 | |
| SDA for channel 3 | |
| SCL for channel 3 | |
| SDA for channel 4 | |
| SCL for channel 4 | |
| SDA for channel 5 | |
| SCL for channel 5 | |
| SDA for channel 6 | |
| SCL for channel 6 | |
| SDA for channel 7 | |
| SCL for channel 7 |
Here are the default I2C pins depending on the microcontroller you’re using:
| GPIO 22 (SCL), GPIO 21 (SDA) | |
| GPIO 5 (D1) (SCL), GPIO 4 (D2) (SDA) | |
| A5 (SCL), A4 (SDA) |
As you can see, it is pretty easy to control multiple OLED displays showing different graphics using an I2C multiplexer.
Here are the default I2C pins depending on the microcontroller you’re using:
| GPIO 22 (SCL), GPIO 21 (SDA) | |
| GPIO 5 (D1) (SCL), GPIO 4 (D2) (SDA) | |
| A5 (SCL), A4 (SDA) |
| Free Projects | Course/eBook | |
| ESP32 Tutorials | Learn ESP32 with Arduino IDE | |
| ESP8266 Tutorials | Home Automation using ESP8266 | |
| Arduino Tutorials | Arduino Step-by-step Projects |
You’ll create a Telegram bot for your ESP32/ESP8266 board;
You can start a conversation with the bot;
When you send the message
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
Start a conversation with that bot and type
The on-board LED should turn on and turn off accordingly (the ESP8266 on-board LED works in reverse, it’s off when you send
At the same time, on the Serial Monitor you should see that the ESP is receiving the messages.
If you try to interact with your bot from another account, you’ll get the the “
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
Start a conversation with that bot and type
At the same time, on the Serial Monitor, you should see that the ESP32-CAM is receiving the messages.
If you try to interact with your bot from another account, you’ll get the “Unauthorized user” message.
Here’s an overview on how the project works:
You’ll create a Telegram bot for your ESP32.
The ESP32 is connected to a PIR motion sensor.
When the sensor detects motion, the ESP32 sends a warning message to your telegram account.
You’ll be notified in your telegram account whenever motion is detected.
This is a simple project, but shows how you can use Telegram in your IoT and Home Automation projects.
The idea is to apply the concepts learned in your own projects.
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
Start a conversation with that bot and type
In this example, we’re wiring the PIR motion sensor data pin to GPIO 27.
You can use any other suitable GPIO.
Read ESP32 GPIO Guide .
At the same time, this is what you should get on the Serial Monitor.
We have other tutorials about Telegram that we recommend reading:
Control ESP32/ESP8266 Outputs using Telegram (Arduino IDE)
Request ESP32/ESP8266 Sensor Readings using Telegram (Arduino IDE)
ESP32 Motion Detection with Notifications using Telegram (Arduino IDE)
ESP8266 NodeMCU Motion Detection with Notifications (Arduino IDE)
In this tutorial you’ll create a telegram bot to interact with the ESP32 or ESP8266 boards;
You’ll create a group where you can add several people you want to have control and receive notifications from the bot;
The bot will be added to the group so that the members can interact with it;
As an example, we’ll show you how to send commands to control outputs and how to send responses from the bot to the group.
A new window should open and you’ll be prompted to click the
Add members to your group and give it a name.
Search for your bot name and add it to the group.
Save the group ID because you’ll need it later.
The on-board LED should turn on and turn off accordingly (the ESP8266 on-board LED works in reverse, it’s off when you send
On the Serial Monitor you should see that the ESP is receiving the messages.
You’ll create a Telegram bot for your ESP32 or ESP8266 NodeMCU board;
You can start a conversation with the bot;
When you send the message
Open Telegram and follow the next steps to create a Telegram Bot.
First, search for “
The following window should open and you’ll be prompted to click the
Type
If your bot is successfully created, you’ll receive a message with a link to access the bot and the
Start a conversation with that bot and type
To use the BME280 library, you also need to install the Adafruit Unified Sensor .
Follow the next steps to install the library in your Arduino IDE:
3.
Search for “
After installing the libraries, restart your Arduino IDE.
For this example we’ll get sensor readings from the BME280 sensor.
Here’s a list of parts you need to build the circuit for this project:
ESP32 board (read Best ESP32 dev boards )
Alternative – ESP8266 board (read Best ESP8266 dev boards )
BME280 sensor
Jumper wires
Breadboard
At the same time, on the Serial Monitor, you should see that the ESP32 or ESP8266 is receiving the messages.
If you try to interact with your bot from another account, you’ll get the the “
For an introduction to LoRa communication, read: ESP32 with LoRa using Arduino IDE .
The board also features several GPIOs to connect peripherals, PRG (BOOT) and RST buttons, and a lithium battery connector.
For a more in-depth overview of this board, read: TTGO LoRa32 SX1276 OLED Review .
The OLED displays communicates using I2C communication protocol .
It is internally connected to the ESP32 on the following pins:
|
| |
| GPIO 4 | |
| GPIO 15 | |
| GPIO 16 |
| MISO | GPIO 19 |
| MOSI | GPIO 27 |
| SCK | GPIO 5 |
| CS | GPIO 18 |
| IRQ | GPIO 26 |
| RST | GPIO 14 |
3.
After installing the SSD1306 library from Adafruit, type “
After installing the libraries, restart your Arduino IDE.
After uploading the code to your board, it should start sending LoRa packets.



Here’s a table with the connections between the ESP32 and the camera:
| D2 | GPIO 17 |
| D3 | GPIO 35 |
| D4 | GPIO 34 |
| D5 | GPIO 5 |
| D6 | GPIO 39 |
| D7 | GPIO 18 |
| D8 | GPIO 36 |
| D9 | GPIO 19 |
| SIOC | GPIO 23 |
| SIOD | GPIO 25 |
| XCLK | GPIO 27 |
| VSYNC | GPIO 22 |
| HREF | GPIO 26 |
| PCLK | GPIO 21 |
| RST | GPIO 15 |
| PWDN | GPIO 0 |
This board comes with an I2C SSD1306 0.91 inch OLED display.
To interact with the display you can use the Adafruit SSD1306 , the oled-ssd1306 or other compatible libraries.
We usually use the Adafruit SSD1306 along with the Adafruit_GFX to interact with OLED displays.
The OLED communicates with the ESP32 using the following pins:
| SDA | GPIO 14 |
| SCL | GPIO 13 |
Learn more about this project: ESP32-CAM Video Streaming Web Server
Learn more about this project: ESP32-CAM Take Photo and Display in Web Server
Copy the following to the camera_pins.h file.
#if defined(CAMERA_MODEL_T_JOURNAL)
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 17
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
Then, in the CameraWebServer tab, comment all the existing camera models, and add your camera, as follows:
// Select camera model
#define CAMERA_MODEL_T_JOURNAL
//#define CAMERA_MODEL_WROVER_KIT
//#define CAMERA_MODEL_ESP_EYE
//#define CAMERA_MODEL_M5STACK_PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE
//#define CAMERA_MODEL_AI_THINKER
Because this camera doesn’t have PSRAM, the face recognition and detection features of this project don’t work with this camera.
All the other functionalities work well.
Then, simply click the Arduino IDE upload button and it is done!
Updated on 26 March 2023
As an example, we’ll be using a BME280 sensor connected to an ESP board.
You can modify the code provided to send readings from a different sensor or use multiple boards.
To create this project, you’ll use these technologies:
ESP32 or ESP8266 programmed with Arduino IDE
Hosting server and domain name
PHP script to insert data into MySQL database and display it on a web page
MySQL database to store readings
PHP script to plot data from database in charts
You might also find helpful reading these projects:
ESP32/ESP8266 Insert Data into MySQL Database using PHP and Arduino IDE
ESP32/ESP8266 Plot Sensor Readings in Real Time Charts – Web Server
The project is divided into the following main sections:
I recommend using one of the following hosting services that can handle all the project requirements:
Bluehost (user-friendly with cPanel) : free domain name when you sign up for the 3-year plan.
I recommend choosing the unlimited websites option;
Digital Ocean : Linux server that you manage through a command line.
I only recommended this option for advanced users.
Those two services are the ones that I use and personally recommend, but you can use any other hosting service.
Any hosting service that offers PHP and MySQL will work with this tutorial.
If you don’t have a hosting account, I recommend signing up for Bluehost .
Get Hosting and Domain Name with Bluehost
When buying a hosting account, you’ll also have to purchase a domain name.
This is what makes this project interesting: you’ll be able to go your domain name (http://example.com) and see your ESP readings.
If you like our projects, you might consider signing up to one of the recommended hosting services, because you’ll be supporting our work.
That’s it! Your new database and user were created successfully.
Now, save all your details because you’ll need them later:
In the left sidebar, select your database name example_esp_data and open the “SQL” tab.
After that, you should see your newly created table called Sensor in the example_esp_data database as shown in the figure below:
Then, select the
Edit the newly created file (post-data.php) and copy the following snippet:
<?php
/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
$servername = "localhost";
// REPLACE with your Database name
$dbname = "REPLACE_WITH_YOUR_DATABASE_NAME";
// REPLACE with Database user
$username = "REPLACE_WITH_YOUR_USERNAME";
// REPLACE with Database user password
$password = "REPLACE_WITH_YOUR_PASSWORD";
// Keep this API Key value to be compatible with the ESP32 code provided in the project page.
If you change this value, the ESP32 sketch needs to match
$api_key_value = "tPmAT5Ab3j7F9";
$api_key = $value1 = $value2 = $value3 = "";
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$api_key = test_input($_POST["api_key"]);
if($api_key == $api_key_value) {
$value1 = test_input($_POST["value1"]);
$value2 = test_input($_POST["value2"]);
$value3 = test_input($_POST["value3"]);
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "INSERT INTO Sensor (value1, value2, value3)
VALUES ('" .
$value1 .
"', '" .
$value2 .
"', '" .
$value3 .
"')";
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
}
else {
echo "Error: " .
$sql .
"<br>" .
$conn->error;
}
$conn->close();
}
else {
echo "Wrong API Key provided.";
}
}
else {
echo "No data posted with HTTP POST.";
}
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
View raw code
Before saving the file, you need to modify the $dbname, $username and $password variables with your unique details:
// Your Database name
$dbname = "example_esp_data";
// Your Database user
$username = "example_esp_board";
// Your Database user password
$password = "YOUR_USER_PASSWORD";
After adding the database name, username and password, save the file and continue with this tutorial.
If you try to access your domain name in the next URL path, you’ll see the message:
http://example.com/post-data.php
Edit the newly created file (esp-chart.php) and copy the following code:
<!--
Rui Santos
Complete project details at https://RandomNerdTutorials.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-->
<?php
$servername = "localhost";
// REPLACE with your Database name
$dbname = "REPLACE_WITH_YOUR_DATABASE_NAME";
// REPLACE with Database user
$username = "REPLACE_WITH_YOUR_USERNAME";
// REPLACE with Database user password
$password = "REPLACE_WITH_YOUR_PASSWORD";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " .
$conn->connect_error);
}
$sql = "SELECT id, value1, value2, value3, reading_time FROM Sensor order by reading_time desc limit 40";
$result = $conn->query($sql);
while ($data = $result->fetch_assoc()){
$sensor_data[] = $data;
}
$readings_time = array_column($sensor_data, 'reading_time');
// ******* Uncomment to convert readings time array to your timezone ********
/*$i = 0;
foreach ($readings_time as $reading){
// Uncomment to set timezone to - 1 hour (you can change 1 to any number)
$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading - 1 hours"));
// Uncomment to set timezone to + 4 hours (you can change 4 to any number)
//$readings_time[$i] = date("Y-m-d H:i:s", strtotime("$reading + 4 hours"));
$i += 1;
}*/
$value1 = json_encode(array_reverse(array_column($sensor_data, 'value1')), JSON_NUMERIC_CHECK);
$value2 = json_encode(array_reverse(array_column($sensor_data, 'value2')), JSON_NUMERIC_CHECK);
$value3 = json_encode(array_reverse(array_column($sensor_data, 'value3')), JSON_NUMERIC_CHECK);
$reading_time = json_encode(array_reverse($readings_time), JSON_NUMERIC_CHECK);
/*echo $value1;
echo $value2;
echo $value3;
echo $reading_time;*/
$result->free();
$conn->close();
?>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/highcharts.js"></script>
<style>
body {
min-width: 310px;
max-width: 1280px;
height: 500px;
margin: 0 auto;
}
h2 {
font-family: Arial;
font-size: 2.5rem;
text-align: center;
}
</style>
<body>
<h2>ESP Weather Station</h2>
<div></div>
<div></div>
<div></div>
<script>
var value1 = <?php echo $value1; ?>;
var value2 = <?php echo $value2; ?>;
var value3 = <?php echo $value3; ?>;
var reading_time = <?php echo $reading_time; ?>;
var chartT = new Highcharts.Chart({
chart:{ renderTo : 'chart-temperature' },
title: { text: 'BME280 Temperature' },
series: [{
showInLegend: false,
data: value1
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#059e8a' }
},
xAxis: {
type: 'datetime',
categories: reading_time
},
yAxis: {
title: { text: 'Temperature (Celsius)' }
//title: { text: 'Temperature (Fahrenheit)' }
},
credits: { enabled: false }
});
var chartH = new Highcharts.Chart({
chart:{ renderTo:'chart-humidity' },
title: { text: 'BME280 Humidity' },
series: [{
showInLegend: false,
data: value2
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
}
},
xAxis: {
type: 'datetime',
//dateTimeLabelFormats: { second: '%H:%M:%S' },
categories: reading_time
},
yAxis: {
title: { text: 'Humidity (%)' }
},
credits: { enabled: false }
});
var chartP = new Highcharts.Chart({
chart:{ renderTo:'chart-pressure' },
title: { text: 'BME280 Pressure' },
series: [{
showInLegend: false,
data: value3
}],
plotOptions: {
line: { animation: false,
dataLabels: { enabled: true }
},
series: { color: '#18009c' }
},
xAxis: {
type: 'datetime',
categories: reading_time
},
yAxis: {
title: { text: 'Pressure (hPa)' }
},
credits: { enabled: false }
});
</script>
</body>
</html>
View raw code
After adding the $dbname, $username and $password save the file and continue with this project.
// Your Database name
$dbname = "example_esp_data";
// Your Database user
$username = "example_esp_board";
// Your Database user password
$password = "YOUR_USER_PASSWORD";
If you try to access your domain name in the following URL path, you’ll see the following:
https://example.com/esp-chart.php
That’s it! If you see three empty charts in your browser, it means that everything is ready.
In the next section, you’ll learn how to publish your ESP32 or ESP8266 sensor readings.
To build the charts, we’ll use the Highcharts library .
We’ll create three charts: temperature, humidity and pressure over time.
The charts display a maximum of 40 data points, and a new reading is added every 30 seconds, but you change these values in your code.
If everything is correct, this is what you should see in your Arduino IDE Serial Monitor:
If you open your domain name in this URL path:
https://example.com/esp-chart.php
You should see all the readings stored in your database.
Refresh the web page to see the latest readings:
You can also go to phpMyAdmin to manage the data stored in your Sensor table.
You can delete it, edit, etc…
The Arduino IDE works great for small applications.
However, for advanced projects with more than 200 lines of code, multiple files, and other advanced features like auto completion and error checking, VS Code with the PlatformIO IDE extension is the best alternative.
In this tutorial, we’ll cover the following topics:
Installing VS Code (Visual Studio Code):
Click on the installation wizard to start the installation and follow all the steps to complete the installation.
Accept the agreement and press the
Select the following options and click
Press the
Finally, click
Open VS Code and you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
You can click the
After downloading the Visual Studio Code application file, you’ll be prompted with the following message.
Press the “
Or open your Downloads folder and open Visual Studio Code.
After that, you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
Then, run the brew command to install Python 3.X:
$ brew install python3
Now, .
Save the installation file:
To install it, open a Terminal windows, navigate to your Downloads folder and run the following command to install VS Code.
$ cd Downloads
~/Downloads $ sudo apt install ./code_1.49.1-1600299189_amd64.deb
When the installation is finished, VS Code should be available in your applications menu.
Open VS Code and you’ll be greeted by a Welcome tab with the released notes of the newest version.
That’s it.
Visual Studio Code was successfully installed.
As you can see in the preceding figure, Python 3.8.2 is already installed.
If you don’t have Python 3.8.X installed, run the next command to install it:
$ sudo apt install python3
Whether you already have Python installed or not, you need to run the following command to install Python utilities.
$ sudo apt install python3-distutils
Now, .
After installing, make sure that PlatformIO IDE extension is enabled as shown below.
After that, the PlatformIO icon should show up on the left sidebar as well as an
That’s it, PlatformIO IDE extension was successfully added to VS Code.
If you don’t see the
File explorer
Search across files
Source code management (using gist)
Launch and debug your code
Manage extensions
Additionally, you can press
If the tasks don’t show up on your IDE when you click the icon, you may need to click on the three dot icon at the top and enable PlatformIO tasks as shown below.
Give your project a name (for example Blink_LED) and select the board you’re using.
In our case, we’re using the
For this example, we’ll be using the DOIT ESP32 DEVKIT board .
If you are using an ESP8266 NodeMCU board the process is very similar, you just need to select your ESP8266 board:
The Blink_LED project should be accessible from the Explorer tab.
VS Code and PlatformIO have a folder structure that is different from the standard .ino project.
If you click on the Explorer tab, you’ll see all the files it created under your project folder.
It may seem a lot of files to work with.
But, don’t worry, usually you’ll just need to deal with one or two of those files.
In PlatformIO, all your Arduino sketches should start with the #include <Arduino.h>.
If the code is successfully uploaded, you should get the following message.
After uploading the code, the ESP32 or ESP8266 should be blinking its on-board LED every second.
Now, click on the Serial Monitor icon and you should see it printing the current LED state.
After that, save that file.
Click on the library you want to include in your project.
Then, click
Select the project were you want to use the library.
This will add the library identifier using the lib_deps directive on the platformio.ini file.
If you open your project’s platformio.ini file, it should look as shown in the following image.
Alternatively, on the library window, if you select the
Then, go to the platformio.ini file of your project and paste the library identifier into that file, like this:
lib_deps = adafruit/Adafruit BME280 Library@^2.1.0
If you need multiple libraries, you can separate their name by a coma or put them on different lines.
For example:
lib_deps =
arduino-libraries/Arduino_JSON @ 0.1.0
adafruit/Adafruit BME280 Library @ ^2.1.0
adafruit/Adafruit Unified Sensor @ ^1.1.4
PlatformIO has a built-in powerful Library Manager, that allows you to specify custom dependencies per project in the Project Configuration File platformio.ini using lib_deps.
This will tell PlatformIO to automatically download the library and all its dependencies when you save the configuration file or when you compile your project.
PlatformIO will open all the files within the project folder.
To get familiar with VS Code with the ESP32 and ESP8266, follow the next tutorial first:
Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266
You can also use VS Code to program your boards with MicroPython firmware:
MicroPython: Program ESP32/ESP8266 using VS Code and Pymakr
At this point, I have three projects under my untitled workspace.
The workspace is saved as a file with the .code-workspace extension.
In my case, I called my workspace file ESP-NOW-project.code-workspace.
Now, it shows up on the Explorer tab with the new name.
As you can see, it includes the paths of the included project folders.
At the moment, it doesn’t have any custom settings yet.
Let’s see how to add custom settings to workspaces in the next section.
There are lots of settings that you can define for your workspace.
For demonstration purposes, we’ve only made a few changes.
Under the
From now on, every time you open that workspace, it will show the light color theme.
Nonetheless, the default VS Code color theme remains the Dark +.
This means that if you close the workspace or open another project, it will get back to the default settings or whatever settings you have defined for that specific workspace.
Now, if you open your workspace file, you’ll see that it contains the new settings.
From now on, that extension will be enabled when you’re working on that workspace.
Then, a drop-down menu will show up at the top of the window with all the project folders on the workspace.
You need to select the project folder you want to upload to your board.
At the top, the sensor was marking approximately 2260 meters, which is approximately 90 meters from the real value (2351 meters).
I don’t think that a difference of 90 meters is relevant at such an altitude.
What do you think? The temperature was marking 13oC (55oF), which was the same temperature predicted in the forecast.
We tried to take pictures of the OLED display showing the results using our smartphone.
Unfortunately, due to the frame rate of the OLED display, the numbers are not visible.
If you want to turn your breadboard circuits into real boards and make your projects look more professional, you just have to upload the Gerber files to order high quality PCBs for low prices.
We’ll show you how to do this later in this blog post.
I’ve designed the shield to be a compact weather station.
The PCB has a lot of features so that it can suit a lot of different projects for different applications.
In fact, I didn’t use all the PCB features in this project.
Additionally, this shield can also be used as a learning shield as it comes with some of the most used components when starting to learn how to program the ESP32.
The shield allows you to control:
2x SMD LEDs
1x Pushbutton
1x Trimpot
1x DHT22 temperature and humidity sensor
1x BMP180 barometric sensor
1x Light dependent resistor
1x MicroSD card module
2x Terminal blocks –that give you access to 3 GPIOs to connect other components
The microSD card module is a very interesting addition to the shield: it can be used to store readings if you want to build a data logger, or it can store an HTML file to serve a web page – as we’ll do in this project.
I think this is a better and easier way to build a web server that requires more complex web pages.
Inside that folder, create a new folder called
Don’t forget go to the Bluetooth settings and enable Bluetooth adapter in your smartphone.
You may also want to make it visible to other devices to test other sketches later on.
Once everything is ready in your smartphone and the ESP32 is running the BLE server sketch, in the app, tap the scan button to scan for nearby devices.
You should find an ESP32 with the name “
The ESP32 goes into deep sleep mode.
You can wake it up by touching the wire connected to Touch Pin 3.
When you touch the pin, the ESP32 displays on the Serial Monitor: the boot number, the wake up cause, and in which GPIO touch was detected.
We can connect the reed switch to an ESP32 GPIO to detect changes in its state.
The advantage of using an I2C LCD is that the wiring is really simple.
You just need to wire the SDA and SCL pins.
Additionally, it comes with a built-in potentiometer you can use to adjust the contrast between the background and the characters on the LCD.
On a “regular” LCD you need to add a potentiometer to the circuit to adjust the contrast.
You should see the files on the ESP32/ESP8266 board on the device folder.
By default, when you burn MicroPython firmware, a boot.py file is created.
For this project you’ll need a boot.py file and a main.py file.The boot.py file has the code that only needs to run once on boot.
This includes importing libraries, network credentials, instantiating pins, connecting to your network, and other configurations.
The main.py file will contain the code that runs the web server to serve files and perform tasks based on the requests received by the client.
6.
Select the
You’ve successfully uploaded files to the ESP32 filesystem using the plugin.
This modulation technique allows long range communication of small amounts of data (which means a low bandwidth), high immunity to interference, while minimizing power consumption.
So, it allows long distance communication with low power requirements.
Keep in mind that LoRa is not suitable for projects that:
Require high data-rate transmission;
Need very frequent transmissions;
Or are in highly populated networks.
Point to point communication
Or build a LoRa network (using LoRaWAN for example)
Unlike Wi-Fi or Bluetooth that only support short distance communication, two LoRa devices with a proper antenna can exchange data over a long distance.
You can easily configure your ESP32 with a LoRa chip to transmit and receive data reliably at more than 200 meters distance (you can get better results depending on your enviroment and LoRa settings).
There are also other LoRa solutions that easily have a range of more than 30Km.
The LoRaWAN protocol is a Low Power Wide Area Network (LPWAN) specification derived from LoRa technology standardized by the LoRa Alliance.
We won’t explore LoRaWAN in this tutorial, but for more information you can check the LoRa Alliance and The Things Network websites.
The later ESP32 has access to Wi-Fi, and it can run a web server that displays the moisture readings.
This is just an example that illustrates how you can use the LoRa technology in your ESP32 projects.
The following code should load.
/*
* OTAWebUpdater.ino Example from ArduinoOTA Library
* Rui Santos
* Complete Project Details https://randomnerdtutorials.com
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
const char* host = "esp32";
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
WebServer server(80);
/*
* Login page
*/
const char* loginIndex =
"<form name='loginForm'>"
"<table width='20%' bgcolor='A09F9F' align='center'>"
"<tr>"
"<td colspan=2>"
"<center><font size=4><b>ESP32 Login Page</b></font></center>"
"<br>"
"</td>"
"<br>"
"<br>"
"</tr>"
"<td>Username:</td>"
"<td><input type='text' size=25 name='userid'><br></td>"
"</tr>"
"<br>"
"<br>"
"<tr>"
"<td>Password:</td>"
"<td><input type='Password' size=25 name='pwd'><br></td>"
"<br>"
"<br>"
"</tr>"
"<tr>"
"<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
"</tr>"
"</table>"
"</form>"
"<script>"
"function check(form)"
"{"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{"
"window.open('/serverIndex')"
"}"
"else"
"{"
" alert('Error Password or Username')/*displays error message*/"
"}"
"}"
"</script>";
/*
* Server Index Page
*/
const char* serverIndex =
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update'>"
"<input type='submit' value='Update'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
"e.preventDefault();"
"var form = $('#upload_form')[0];"
"var data = new FormData(form);"
" $.ajax({"
"url: '/update',"
"type: 'POST',"
"data: data,"
"contentType: false,"
"processData:false,"
"xhr: function() {"
"var xhr = new window.XMLHttpRequest();"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var per = evt.loaded / evt.total;"
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!')"
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
/*
* setup function
*/
void setup(void) {
Serial.begin(115200);
// Connect to WiFi network
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/*use mdns for host name resolution*/
if (!MDNS.begin(host)) { //http://esp32.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
/*return index page which is stored in serverIndex */
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", loginIndex);
});
server.on("/serverIndex", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
/*handling uploading firmware file */
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
server.begin();
}
void loop(void) {
server.handleClient();
delay(1);
}
View raw code
You should change the following lines on the code to include your own network credentials:
const char* ssid = "";
const char* password = "";
The OTAWebUpdater example for the ESP32 creates an asynchronous web server where you can upload new code to your board without the need for a serial connection.
Upload the previous code to your ESP32 board.
Don’t forget to enter your network credentials and select the right board and serial port.
With this example we’ll also explore two important concepts: interrupts and timers.
Before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE.
Follow one of the following tutorials to install the ESP32 on the Arduino IDE, if you haven’t already.
Installing the ESP32 Board in Arduino IDE (Windows instructions)
Installing the ESP32 Board in Arduino IDE (Mac and Linux instructions)
If you want to learn more about the ESP32, read Getting Started Guide with ESP32 .
The ESP32 hosts a web server that displays a web page with a slider;
When you move the slider, you make an HTTP request to the ESP32 with the new slider value;
The HTTP request comes in the following format: GET/slider?value=SLIDERVALUE, in which SLIDERVALUE is a number between 0 and 255.
You can modify your slider to include any other range;
From the HTTP request, the ESP32 gets the current value of the slider;
The ESP32 adjusts the PWM duty cycle accordingly to the slider value;
This can be useful to control the brightness of an LED (as we’ll do in this example), a servo motor, setting up a threshold value or other applications.
If you’re using a different operating system, make sure you follow the right guide:
Install uPyCraft IDE – Windows PC Instructions
Install uPyCraft IDE – Mac OS X Instructions
After installing uPyCraft IDE in your computer, we recommend reading: Getting Started with MicroPython on ESP32 and ESP8266 .
We’ll be using this software to flash our ESP based boards with MicroPython firmware as well as to program the boards.
4) Search for ESP32 and press install button for the “
5) That’s it.
It should be installed after a few seconds:
Here’s how the process works:
When the ESP32 boots for the first time, it’s set as an Access Point ;
You can connect to that Access Point by establishing a connection with the WiFiManager network and going to the IP address 192.164.4.1;
A web page opens that allows you to choose and configure a network;
The ESP32 saves those network credentials so that later it can connect to that network (Station mode);
Once a new SSID and password is set, the ESP32 reboots, it is set to Station mode and tries to connect to the previously saved network;
If it establishes a connection, the process is completed successfully.
Otherwise, it will be set up as an Access Point for you to configure new network credentials.
To set up the Wi-Fi Manager on the ESP32 using MicroPython, we’ll use the WiFiManager library by tayfunulu .
In the library GitHub page, you can find the following diagram that shows an overview on how everything works.
After that, open the downloaded installation file and run it.
The installation is pretty straightforward.
Complete the on-screen instructions to finish the Atom installation.
Here’s an overview of the project you’ll build:
You’ll create a Telegram bot for your ESP32-CAM;
You can start a conversation with the ESP32-CAM bot;
When you send the message